mirror of
https://github.com/OneUptime/oneuptime
synced 2024-11-22 07:10:53 +00:00
179 lines
5.9 KiB
TypeScript
179 lines
5.9 KiB
TypeScript
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";
|
|
import UserNotificationExecutionStatus from "Common/Types/UserNotification/UserNotificationExecutionStatus";
|
|
import { EVERY_MINUTE } from "Common/Utils/CronTime";
|
|
import { IsDevelopment } from "Common/Server/EnvironmentConfig";
|
|
import IncidentService from "Common/Server/Services/IncidentService";
|
|
import UserNotificationRuleService from "Common/Server/Services/UserNotificationRuleService";
|
|
import UserOnCallLogService from "Common/Server/Services/UserOnCallLogService";
|
|
import logger from "Common/Server/Utils/Logger";
|
|
import Incident from "Common/Models/DatabaseModels/Incident";
|
|
import UserNotificationRule from "Common/Models/DatabaseModels/UserNotificationRule";
|
|
import UserOnCallLog from "Common/Models/DatabaseModels/UserOnCallLog";
|
|
|
|
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 = (
|
|
pendingNotificationLog: UserOnCallLog,
|
|
) => Promise<void>;
|
|
|
|
const executePendingNotificationLog: ExecutePendingNotificationLogFunction =
|
|
async (pendingNotificationLog: UserOnCallLog): Promise<void> => {
|
|
try {
|
|
const ruleType: NotificationRuleType =
|
|
UserOnCallLogService.getNotificationRuleType(
|
|
pendingNotificationLog.userNotificationEventType!,
|
|
);
|
|
|
|
const incident: Incident | null = await IncidentService.findOneById({
|
|
id: pendingNotificationLog.triggeredByIncidentId!,
|
|
props: {
|
|
isRoot: true,
|
|
},
|
|
select: {
|
|
incidentSeverityId: true,
|
|
},
|
|
});
|
|
|
|
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;
|
|
}
|
|
|
|
isAllExecuted = false;
|
|
|
|
if (
|
|
notificationRule.notifyAfterMinutes! > minutesSinceExecutionStarted
|
|
) {
|
|
continue;
|
|
}
|
|
|
|
// 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,
|
|
},
|
|
);
|
|
}
|
|
|
|
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}`,
|
|
);
|
|
logger.error(err);
|
|
|
|
await UserOnCallLogService.updateOneById({
|
|
id: pendingNotificationLog.id!,
|
|
data: {
|
|
status: UserNotificationExecutionStatus.Error,
|
|
statusMessage: err.message ? err.message : "Unknown error",
|
|
},
|
|
props: {
|
|
isRoot: true,
|
|
},
|
|
});
|
|
}
|
|
};
|