oneuptime/App/FeatureSet/Workers/Jobs/UserOnCallLog/ExecutePendingExecutions.ts

188 lines
7.2 KiB
TypeScript
Raw Normal View History

2024-01-11 10:49:55 +00:00
import RunCron from '../../Utils/Cron';
import LIMIT_MAX, { LIMIT_PER_PROJECT } from 'Common/Types/Database/LimitMax';
import OneUptimeDate from 'Common/Types/Date';
import NotificationRuleType from 'Common/Types/NotificationRule/NotificationRuleType';
import ObjectID from 'Common/Types/ObjectID';
2024-01-11 10:49:55 +00:00
import UserNotificationExecutionStatus from 'Common/Types/UserNotification/UserNotificationExecutionStatus';
import { EVERY_MINUTE } from 'Common/Utils/CronTime';
import { IsDevelopment } from 'CommonServer/EnvironmentConfig';
import IncidentService from 'CommonServer/Services/IncidentService';
2024-01-11 10:49:55 +00:00
import UserNotificationRuleService from 'CommonServer/Services/UserNotificationRuleService';
import UserOnCallLogService from 'CommonServer/Services/UserOnCallLogService';
import logger from 'CommonServer/Utils/Logger';
2024-01-11 10:49:55 +00:00
import Incident from 'Model/Models/Incident';
import UserNotificationRule from 'Model/Models/UserNotificationRule';
import UserOnCallLog from 'Model/Models/UserOnCallLog';
2024-01-11 10:49:55 +00:00
RunCron(
'UserOnCallLog:ExecutePendingExecutions',
{
schedule: IsDevelopment ? EVERY_MINUTE : EVERY_MINUTE,
runOnStartup: false,
},
async () => {
const pendingNotificationLogs: Array<UserOnCallLog> =
await UserOnCallLogService.findBy({
query: {
status: UserNotificationExecutionStatus.Executing,
},
select: {
_id: true,
projectId: true,
createdAt: true,
executedNotificationRules: true,
userId: true,
userNotificationEventType: true,
triggeredByIncidentId: true,
onCallDutyPolicyEscalationRuleId: true,
onCallDutyPolicyExecutionLogTimelineId: true,
onCallDutyPolicyExecutionLogId: true,
onCallDutyPolicyId: true,
userBelongsToTeamId: true,
},
props: {
isRoot: true,
},
skip: 0,
limit: LIMIT_MAX,
});
const promises: Array<Promise<void>> = [];
for (const pendingNotificationLog of pendingNotificationLogs) {
promises.push(
executePendingNotificationLog(pendingNotificationLog)
);
}
await Promise.allSettled(promises);
}
);
type ExecutePendingNotificationLogFunction = (
2024-01-11 10:49:55 +00:00
pendingNotificationLog: UserOnCallLog
) => Promise<void>;
2024-01-11 10:49:55 +00:00
const executePendingNotificationLog: ExecutePendingNotificationLogFunction =
async (pendingNotificationLog: UserOnCallLog): Promise<void> => {
try {
const ruleType: NotificationRuleType =
UserOnCallLogService.getNotificationRuleType(
pendingNotificationLog.userNotificationEventType!
);
2024-01-11 10:49:55 +00:00
const incident: Incident | null = await IncidentService.findOneById(
{
id: pendingNotificationLog.triggeredByIncidentId!,
props: {
isRoot: true,
},
select: {
incidentSeverityId: true,
},
}
2024-01-11 10:49:55 +00:00
);
const notificationRules: Array<UserNotificationRule> =
await UserNotificationRuleService.findBy({
query: {
projectId: pendingNotificationLog.projectId!,
userId: pendingNotificationLog.userId!,
ruleType: ruleType,
incidentSeverityId:
incident?.incidentSeverityId as ObjectID,
},
select: {
_id: true,
notifyAfterMinutes: true,
},
props: {
isRoot: true,
},
skip: 0,
limit: LIMIT_PER_PROJECT,
});
let isAllExecuted: boolean = true;
const minutesSinceExecutionStarted: number =
OneUptimeDate.getDifferenceInMinutes(
pendingNotificationLog.createdAt!,
OneUptimeDate.getCurrentDate()
);
for (const notificationRule of notificationRules) {
// check if this rule is already executed.
const isAlreadyExecuted: boolean = Object.keys(
pendingNotificationLog.executedNotificationRules! || {}
).includes(notificationRule.id?.toString() || '');
if (isAlreadyExecuted) {
continue;
}
2024-01-11 10:49:55 +00:00
isAllExecuted = false;
2024-01-11 10:49:55 +00:00
if (
notificationRule.notifyAfterMinutes! >
minutesSinceExecutionStarted
) {
continue;
}
2024-01-11 10:49:55 +00:00
// execute this rule.
await UserNotificationRuleService.executeNotificationRuleItem(
notificationRule.id!,
{
userNotificationLogId: pendingNotificationLog.id!,
projectId: pendingNotificationLog.projectId!,
triggeredByIncidentId:
pendingNotificationLog.triggeredByIncidentId,
userNotificationEventType:
pendingNotificationLog.userNotificationEventType!,
onCallPolicyExecutionLogId:
pendingNotificationLog.onCallDutyPolicyExecutionLogId,
onCallPolicyId:
pendingNotificationLog.onCallDutyPolicyId,
onCallPolicyEscalationRuleId:
pendingNotificationLog.onCallDutyPolicyEscalationRuleId,
userBelongsToTeamId:
pendingNotificationLog.userBelongsToTeamId,
onCallDutyPolicyExecutionLogTimelineId:
pendingNotificationLog.onCallDutyPolicyExecutionLogTimelineId,
}
);
2024-01-11 10:49:55 +00:00
}
if (isAllExecuted) {
// mark this log as complete.
await UserOnCallLogService.updateOneById({
id: pendingNotificationLog.id!,
data: {
status: UserNotificationExecutionStatus.Completed,
},
props: {
isRoot: true,
},
});
}
} catch (err: any) {
logger.error(
`Error executing pending notification log: ${pendingNotificationLog._id}`
2024-01-11 10:49:55 +00:00
);
logger.error(err);
2024-01-11 10:49:55 +00:00
await UserOnCallLogService.updateOneById({
id: pendingNotificationLog.id!,
data: {
status: UserNotificationExecutionStatus.Error,
statusMessage: err.message ? err.message : 'Unknown error',
2024-01-11 10:49:55 +00:00
},
props: {
isRoot: true,
},
});
}
};