Initial
This commit is contained in:
71
server/services/runPlanScheduleWorker.js
Normal file
71
server/services/runPlanScheduleWorker.js
Normal file
@@ -0,0 +1,71 @@
|
||||
import { getStringSetting } from '../models/settingsModel.js';
|
||||
import {
|
||||
listDueRunPlanSchedules,
|
||||
recordRunPlanScheduleDispatch
|
||||
} from '../models/runPlanScheduleModel.js';
|
||||
import { executeRunPlan } from './powershellRunner.js';
|
||||
import { logger } from './logger.js';
|
||||
|
||||
let timer = null;
|
||||
let running = false;
|
||||
|
||||
export function runPlanScheduleIntervalMinutes() {
|
||||
const minutes = Number(getStringSetting('runplan_schedule_interval_minutes', process.env.RUNPLAN_SCHEDULE_INTERVAL_MINUTES || '1'));
|
||||
return Number.isFinite(minutes) ? minutes : 1;
|
||||
}
|
||||
|
||||
export async function dispatchDueRunPlanSchedules({ nowIso = new Date().toISOString(), signal } = {}) {
|
||||
const due = listDueRunPlanSchedules(nowIso);
|
||||
const summary = { evaluated: due.length, dispatched: 0, skipped: 0, errors: 0 };
|
||||
for (const schedule of due) {
|
||||
if (signal?.aborted) {
|
||||
summary.skipped += 1;
|
||||
break;
|
||||
}
|
||||
try {
|
||||
const job = executeRunPlan(schedule.runplanId, schedule.createdBy || schedule.ownerUserId || null);
|
||||
recordRunPlanScheduleDispatch(schedule, {
|
||||
jobId: job.id,
|
||||
plannedFor: schedule.nextRunAt || nowIso,
|
||||
status: 'queued',
|
||||
message: `Scheduled RunPlan ${schedule.runplanName || schedule.runplanId} queued as ${job.id}.`
|
||||
});
|
||||
summary.dispatched += 1;
|
||||
} catch (error) {
|
||||
recordRunPlanScheduleDispatch(schedule, {
|
||||
plannedFor: schedule.nextRunAt || nowIso,
|
||||
status: 'failed',
|
||||
message: error.message
|
||||
});
|
||||
summary.errors += 1;
|
||||
logger.error('runplan schedule dispatch failed', { scheduleId: schedule.id, error: error.message });
|
||||
}
|
||||
}
|
||||
return summary;
|
||||
}
|
||||
|
||||
export function startRunPlanScheduleWorker() {
|
||||
const minutes = runPlanScheduleIntervalMinutes();
|
||||
if (minutes <= 0) return null;
|
||||
running = true;
|
||||
scheduleNext(minutes);
|
||||
logger.info(`runplan schedule dispatcher scheduled every ${minutes} minute(s)`);
|
||||
return timer;
|
||||
}
|
||||
|
||||
export function stopRunPlanScheduleWorker() {
|
||||
running = false;
|
||||
if (timer) clearTimeout(timer);
|
||||
timer = null;
|
||||
}
|
||||
|
||||
function scheduleNext(minutes) {
|
||||
if (!running || minutes <= 0) return;
|
||||
timer = setTimeout(() => {
|
||||
dispatchDueRunPlanSchedules()
|
||||
.then((summary) => logger.info('runplan schedule dispatch complete', summary))
|
||||
.catch((error) => logger.error('runplan schedule dispatch failed', { error: error.message }))
|
||||
.finally(() => scheduleNext(runPlanScheduleIntervalMinutes()));
|
||||
}, minutes * 60 * 1000);
|
||||
timer.unref?.();
|
||||
}
|
||||
Reference in New Issue
Block a user