fix: restore legacy cron schedules and shell diagnostics (#3078)

This commit is contained in:
whyour
2026-09-27 16:16:22 +08:00
parent a67d44cde5
commit a8310e7d51
9 changed files with 108 additions and 18 deletions
+70
View File
@@ -0,0 +1,70 @@
const test = require('node:test');
const assert = require('node:assert/strict');
const { format } = require('node:util');
const load = require('../helpers/load-security-module.cjs');
const { SchedulerReadiness } = require('../../back/shared/schedulerReadiness');
const legacySchedules = [
'* * * * *',
'*/5 * * * *',
'0 */10 * * * ?',
'0 */2 * * * ?',
'0 */5 * * * ?',
'0 0/30 * * * ?',
'0 0/5 * * * ?',
'0 0 12 ? * MON',
];
test('API accepts legacy question-mark schedules but rejects malformed cron', () => {
const { scheduleSchema } = load('back/validation/schedule.ts', {
'../config': { logPath: '/ql/data/log' },
});
for (const schedule of [...legacySchedules, '@once', '@boot']) {
assert.equal(scheduleSchema.validate(schedule).error, undefined, schedule);
}
for (const schedule of ['?', '0 /5 * * * ?', '0 70 * * * ?', 'not a cron']) {
assert.ok(scheduleSchema.validate(schedule).error, schedule);
}
});
test('legacy main and extra schedules restore real jobs and healthy readiness', async (t) => {
const stacks = new Map();
t.after(() => {
for (const jobs of stacks.values()) for (const job of jobs) job.cancel();
});
const { addCron } = load('back/schedule/addCron.ts', {
'./data': { scheduleStacks: stacks },
'../shared/runCron': { runCron() {} },
'../loaders/logger': { info() {}, warn() {} },
'../shared/i18n': { tf: format },
});
const crons = legacySchedules.map((schedule, index) => ({
id: `legacy-${index}`, name: 'legacy', schedule, command: 'true',
extra_schedules: [{ schedule: '0 0/30 * * * ?' }],
}));
const register = (rows) => new Promise((resolve, reject) => {
addCron({ request: { replace: true, crons: rows } }, (error) =>
error ? reject(error) : resolve());
});
const readiness = new SchedulerReadiness(async () => {}, 60000);
t.after(() => clearTimeout(readiness.retry));
readiness.configure(() => register(crons));
assert.equal(await readiness.recover(), true);
assert.equal(await readiness.check(), true);
assert.equal(stacks.size, crons.length);
for (const jobs of stacks.values()) {
assert.equal(jobs.length, 2);
assert.ok(jobs.every((job) => job.nextInvocation()));
}
const previousJobs = [...stacks.values()].flat();
for (const schedule of ['?', '0 /5 * * * ?', '0 70 * * * ?']) {
for (const invalid of [
{ ...crons[0], schedule },
{ ...crons[0], extra_schedules: [{ schedule }] },
]) {
await assert.rejects(register([invalid]), (error) => error.code === 3);
assert.deepEqual([...stacks.values()].flat(), previousJobs);
assert.ok(previousJobs.every((job) => job.nextInvocation()));
}
}
});