Use a script to handle services schedules error¶
Prerequisites¶
git checkout origin/osp-alarms-web-configuration .
git checkout origin/osp-collections-rights-configuration .
git checkout origin/osp-scripts-configuration .
You also need a valid configuration with collections rights with the ability to use services. This example is based on this other example to setup up the configuration.
Description¶
The goal of this example is to create a script which goal is to look at all mandatory services and verify that they are in a valid state according to the schedules and active users of the service.
Note
The complete configuration for this example is available on the branch example-collections-script-handle-services
.
git checkout origin/example-collections-script-handle-services .
Steps¶
1. Define a detached script with a scheduled execution¶
root/scripts/services/detached.scripts
{
"moduleId": "modules.scripts.scripts-1",
"accessedValues": [],
"scheduledExecutions": ["0/15 * * ? * * *"],
"sourceFile": "root/scripts/services/check_validity_services.js"
}
2. Create the actual JS script¶
This script validates services by following multiple steps.
Get every services¶
First step is to list the services we want to validate. In this example, we only care about mandatory services, but you can define the filter as you need.
When requesting a list of entries from a collection, we need to provide a page size
and page number
. Meaning that if there is more than page size
entries that match the query, we will need to send more request while increasing the page number
to get the others entries.
In this example, we request 100 entries and handle them. Then, if the count of services we handled is different than the totalCount of entries that match the query, we increase the page number
and keep looping. Otherwise, we exit the loop.
Verify if the current day and time match a schedule from the service¶
Next step, we iterate over every service and take the current day and filter every schedule where openDay <= currentDay <= closeDay
. Schedule openDay
and closeDay
are represent by a number from 0 (Monday) to 6 (Sunday). This is specified by the services rights schema validator.
For every schedule that match this filter, we verify that, using the current time, there are at least one active user inside the service if the current time match the schedule boundaries. We have two types of errors that could occur:
There are active users in the service at a time where it doesn’t match the schedule. We create an alarm to warn that these users shouldn’t be active.
There are no active users in the service at a time where it match the schedule. We create an alarm to warn that an active service is empty.
Check if we should request more services from the collection¶
At the end, we verify that the total amount of services we handled match the totalCount of entries retrieved by the query. If not, we increase the page number and continue the loop to fetch the next services and test them.
Script complete¶
root/scripts/services/check_validity_services.js
main();
function main() {
let mustFetchServicesFromCollection = true;
const PAGING_SIZE = 100;
let PAGING_NUMBER = 0;
let numberOfServicesTreated = 0;
const secondsUntilNow = secondsEllapsedFromToday();
const currentDayAsNumber = getCurrentDayAsNumber();
while (mustFetchServicesFromCollection) {
const listResult = collections.listCustomFilter("root.collections.services", PAGING_SIZE, PAGING_NUMBER, `{mandatory: true}`);
if (isListRequestIsSuccessful(listResult)) {
const collections = listResult.content.collections;
const totalCount = listResult.content.totalCount;
collections.forEach(service => {
verifyIfServiceHasError(service, currentDayAsNumber, secondsUntilNow);
});
numberOfServicesTreated += collections.length;
PAGING_NUMBER += 1;
if (numberOfServicesTreated === totalCount) {
mustFetchServicesFromCollection = false;
}
} else {
mustFetchServicesFromCollection = false;
}
}
}
function isListRequestIsSuccessful(listResult) {
return listResult.success
&& listResult.content
&& listResult.content.hasOwnProperty("collections")
&& listResult.content.hasOwnProperty("totalCount")
}
function secondsEllapsedFromToday() {
var localDateTime = new Date(timestamp.format("YYYY-MM-dd HH:mm:ss", Date.now(), "CET"));
const startOfDay = new Date(localDateTime.getFullYear(), localDateTime.getMonth(), localDateTime.getDate());
const differenceMilliseconds = localDateTime - startOfDay;
const secondsElapsed = Math.floor(differenceMilliseconds / 1000);
return secondsElapsed;
}
function getCurrentDayAsNumber() {
const now = new Date(timestamp.format("YYYY-MM-dd HH:mm:ss", Date.now(), "CET"));
const dayOfWeek = now.getDay();
// Adjust the numbering so that Monday is 0 and Sunday is 6
const adjustedDayOfWeek = (dayOfWeek - 1 + 7) % 7;
return adjustedDayOfWeek;
}
function verifyIfServiceHasError(service, currentDayAsNumber, secondsUntilNow) {
const matchingSchedules = getMatchingScheduleForDayAsNumber(service.schedules, currentDayAsNumber);
if (matchingSchedules.length == 0 && service.activeUsers.length != 0) {
//Raise error, no one should be active in this service
raiseErrorHasActiveUsers(service.name);
}
matchingSchedules.forEach(schedule => {
const openTime = timeConverter(schedule.openTime);
const closeTime = timeConverter(schedule.closeTime);
//Schedule is only one day
if (schedule.openDay === schedule.closeDay) {
if ((openTime < secondsUntilNow && secondsUntilNow < closeTime) && service.activeUsers.length == 0) {
//Raise error, someone should have pick this service
raiseErrorServiceIsEmpty(service.name);
}
if ((openTime > secondsUntilNow || closeTime < secondsUntilNow) && service.activeUsers.length != 0) {
//Raise error, no one should be active in this service
raiseErrorHasActiveUsers(service.name);
}
} else {
//Schedule is one multiple days. Current day can match either openDay or closeDay.
//If it doesn't match any, it means it's in between openDay and closeDay.
//Can't be before openDay or after closeDay because of the filter we do to get the matching schedules
if (schedule.openDay === currentDayAsNumber) {
if (openTime < secondsUntilNow && service.activeUsers.length == 0) {
//Raise error, someone should have pick this service
raiseErrorServiceIsEmpty(service.name);
}
if (openTime > secondsUntilNow && service.activeUsers.length != 0) {
//Raise error, no one should be active in this service
raiseErrorHasActiveUsers(service.name);
}
} else if (schedule.closeDay === currentDayAsNumber) {
if (closeTime > secondsUntilNow && service.activeUsers.length == 0) {
//Raise error, someone should have pick this service
raiseErrorServiceIsEmpty(service.name);
}
if (closeTime < secondsUntilNow && service.activeUsers.length != 0) {
//Raise error, no one should be active in this service
raiseErrorHasActiveUsers(service.name);
}
} else {
//current day is in between open and close day
if (service.activeUsers.length == 0) {
//Raise error, someone should have pick this service
raiseErrorServiceIsEmpty(service.name);
}
}
}
})
}
function getMatchingScheduleForDayAsNumber(schedules, dayAsNumber) {
return schedules.filter(schedule => schedule.openDay <= dayAsNumber && dayAsNumber <= schedule.closeDay)
}
function raiseErrorHasActiveUsers(serviceName) {
return alarms.create(500, `Service [${serviceName}] has active members`, '', 'root.scripts.services', `root.scripts.services-${serviceName}-not-empty`, []);
}
function raiseErrorServiceIsEmpty(serviceName) {
return alarms.create(500, `Service [${serviceName}] is empty`, '', 'root.scripts.services', `root.scripts.services-${serviceName}-empty`, []);
}
// remove ":" and transforme from "0000" in seconds
function timeConverter(time) {
const convTime = time.replace(':', '');
const epoch = ((convTime[0] + convTime[1]) * 3600) + ((convTime[2] + convTime[3]) * 60);
return epoch
}