mirror of
https://github.com/whyour/qinglong.git
synced 2026-09-15 19:57:07 +08:00
* fix: harden task lifecycle and scheduler readiness * fix: confine log writes to the configured log directory * fix: verify complete build artifacts and untracked inputs * fix: reconcile scheduler state and make stop win startup races * fix: isolate cron generations and serialize scheduler recovery
39 lines
1.1 KiB
TypeScript
39 lines
1.1 KiB
TypeScript
import lockfile from 'proper-lockfile';
|
|
import config from '../config';
|
|
|
|
// HTTP and gRPC both mutate cron definitions. Hold one shared lock from the
|
|
// initial DB read/write through scheduler registration (including rollback).
|
|
// Recovery takes the same lock before reading its replacement snapshot.
|
|
export async function withSchedulerMutation<T>(
|
|
operation: () => Promise<T>,
|
|
): Promise<T> {
|
|
let release: () => Promise<void>;
|
|
try {
|
|
release = await lockfile.lock(config.crontabFile, {
|
|
realpath: false,
|
|
lockfilePath: `${config.crontabFile}.scheduler.lock`,
|
|
stale: 30000,
|
|
update: 10000,
|
|
retries: { retries: 50, factor: 1, minTimeout: 100, maxTimeout: 100 },
|
|
});
|
|
} catch (cause) {
|
|
throw Object.assign(
|
|
new Error('Scheduler configuration is busy', { cause }),
|
|
{
|
|
status: 503,
|
|
},
|
|
);
|
|
}
|
|
try {
|
|
return await operation();
|
|
} finally {
|
|
await release();
|
|
}
|
|
}
|
|
|
|
export function schedulerRegistrationError(message: string, cause: any): Error {
|
|
return Object.assign(new Error(message, { cause }), {
|
|
status: cause?.status === 503 ? 503 : 500,
|
|
});
|
|
}
|