mirror of
https://github.com/OneUptime/oneuptime.git
synced 2026-04-06 00:32:12 +02:00
- Added ManualAPI for manually triggering workflows via GET and POST requests. - Introduced WorkflowAPI for updating workflows with authorization checks. - Created documentation for JavaScript and Webhook components. - Established WorkflowFeatureSet to initialize routing and job processing. - Developed QueueWorkflow service for managing workflow queue operations. - Implemented RunWorkflow service to execute workflows with error handling and logging. - Added utility for loading component metadata dynamically.
136 lines
4.3 KiB
TypeScript
136 lines
4.3 KiB
TypeScript
import RunCron from "../../Utils/Cron";
|
|
import OneUptimeDate from "Common/Types/Date";
|
|
import { EVERY_FIVE_MINUTE } from "Common/Utils/CronTime";
|
|
import AlertEpisodeService from "Common/Server/Services/AlertEpisodeService";
|
|
import AlertGroupingRuleService from "Common/Server/Services/AlertGroupingRuleService";
|
|
import logger from "Common/Server/Utils/Logger";
|
|
import AlertEpisode from "Common/Models/DatabaseModels/AlertEpisode";
|
|
import AlertGroupingRule from "Common/Models/DatabaseModels/AlertGroupingRule";
|
|
import QueryHelper from "Common/Server/Types/Database/QueryHelper";
|
|
|
|
RunCron(
|
|
"AlertEpisode:ResolveInactiveEpisodes",
|
|
{
|
|
schedule: EVERY_FIVE_MINUTE,
|
|
runOnStartup: false,
|
|
},
|
|
async () => {
|
|
/*
|
|
* Find active episodes that have been inactive for too long
|
|
* and resolve them due to inactivity
|
|
*/
|
|
|
|
try {
|
|
// Get all active episodes
|
|
const activeEpisodes: Array<AlertEpisode> =
|
|
await AlertEpisodeService.findBy({
|
|
query: {
|
|
resolvedAt: QueryHelper.isNull(),
|
|
},
|
|
select: {
|
|
_id: true,
|
|
projectId: true,
|
|
alertGroupingRuleId: true,
|
|
lastAlertAddedAt: true,
|
|
},
|
|
props: {
|
|
isRoot: true,
|
|
},
|
|
limit: 1000,
|
|
skip: 0,
|
|
});
|
|
|
|
logger.debug(
|
|
`AlertEpisode:ResolveInactiveEpisodes - Found ${activeEpisodes.length} active episodes`,
|
|
);
|
|
|
|
const promises: Array<Promise<void>> = [];
|
|
|
|
for (const episode of activeEpisodes) {
|
|
promises.push(checkAndResolveInactiveEpisode(episode));
|
|
}
|
|
|
|
await Promise.allSettled(promises);
|
|
} catch (error) {
|
|
logger.error(`AlertEpisode:ResolveInactiveEpisodes - Error: ${error}`);
|
|
}
|
|
},
|
|
);
|
|
|
|
type CheckAndResolveInactiveEpisodeFunction = (
|
|
episode: AlertEpisode,
|
|
) => Promise<void>;
|
|
|
|
const checkAndResolveInactiveEpisode: CheckAndResolveInactiveEpisodeFunction =
|
|
async (episode: AlertEpisode): Promise<void> => {
|
|
try {
|
|
if (!episode.id || !episode.projectId) {
|
|
return;
|
|
}
|
|
|
|
// Get inactivity timeout from the grouping rule (only if enabled)
|
|
let inactivityTimeoutMinutes: number = 0;
|
|
let enableInactivityTimeout: boolean = false;
|
|
|
|
if (episode.alertGroupingRuleId) {
|
|
const rule: AlertGroupingRule | null =
|
|
await AlertGroupingRuleService.findOneById({
|
|
id: episode.alertGroupingRuleId,
|
|
select: {
|
|
enableInactivityTimeout: true,
|
|
inactivityTimeoutMinutes: true,
|
|
},
|
|
props: {
|
|
isRoot: true,
|
|
},
|
|
});
|
|
|
|
if (rule) {
|
|
enableInactivityTimeout = rule.enableInactivityTimeout || false;
|
|
if (
|
|
enableInactivityTimeout &&
|
|
rule.inactivityTimeoutMinutes !== undefined
|
|
) {
|
|
inactivityTimeoutMinutes = rule.inactivityTimeoutMinutes;
|
|
}
|
|
}
|
|
}
|
|
|
|
// If inactivity timeout is not enabled or is 0, don't resolve inactive episodes
|
|
if (!enableInactivityTimeout || inactivityTimeoutMinutes <= 0) {
|
|
return;
|
|
}
|
|
|
|
// Check if episode has been inactive for too long
|
|
const lastAlertAddedAt: Date =
|
|
episode.lastAlertAddedAt || episode.createdAt || new Date();
|
|
const minutesSinceLastAlert: number =
|
|
OneUptimeDate.getDifferenceInMinutes(
|
|
lastAlertAddedAt,
|
|
OneUptimeDate.getCurrentDate(),
|
|
);
|
|
|
|
if (minutesSinceLastAlert < inactivityTimeoutMinutes) {
|
|
logger.debug(
|
|
`AlertEpisode:ResolveInactiveEpisodes - Episode ${episode.id} is still active (${minutesSinceLastAlert} minutes since last alert, timeout: ${inactivityTimeoutMinutes})`,
|
|
);
|
|
return;
|
|
}
|
|
|
|
// Episode has been inactive for too long - resolve it
|
|
logger.info(
|
|
`AlertEpisode:ResolveInactiveEpisodes - Resolving episode ${episode.id} due to inactivity (${minutesSinceLastAlert} minutes since last alert)`,
|
|
);
|
|
|
|
await AlertEpisodeService.resolveEpisode(
|
|
episode.id,
|
|
undefined, // No user - auto-resolved due to inactivity
|
|
true, // Cascade to alerts - resolve all member alerts as well
|
|
);
|
|
} catch (error) {
|
|
logger.error(
|
|
`AlertEpisode:ResolveInactiveEpisodes - Error processing episode ${episode.id}: ${error}`,
|
|
);
|
|
}
|
|
};
|