feat(ql3): observe legacy schedule service runs

This commit is contained in:
whyour
2026-08-18 05:57:19 +08:00
parent ca19423f1d
commit 6831ea3de5
9 changed files with 453 additions and 6 deletions
@@ -22,6 +22,9 @@ const SHADOW_ORIGINS_ENV = 'QL3_SHADOW_ORIGINS';
const SUPPORTED_SHADOW_ORIGINS = new Set<ExecutionOrigin>([
'manual',
'scheduled_node',
'script',
'subscription',
'system',
]);
const NOOP_OBSERVATION: LegacyExecutionObservation = Object.freeze({
@@ -81,7 +84,7 @@ function readConfiguredOrigins(): ReadonlySet<ExecutionOrigin> {
incrementFailure('configuration:unsupported_origin');
try {
Logger.warn(
'[ql3-shadow] ignored unsupported origin; this slice supports manual,scheduled_node',
'[ql3-shadow] ignored unsupported origin; this slice supports manual,scheduled_node,script,subscription,system',
);
} catch {
// Invalid compatibility configuration must not affect legacy paths.
+31
View File
@@ -11,6 +11,10 @@ import {
import dayjs from 'dayjs';
import taskLimit from '../shared/pLimit';
import { spawn } from 'cross-spawn';
import { createHash } from 'crypto';
import { observeLegacyExecution } from '../runtime/compatibility/legacyExecutionBridge';
import { observeLegacyChildProcess } from '../runtime/compatibility/observeLegacyChildProcess';
import { createLegacyTaskRevision } from '../runtime/compatibility/legacyTaskRevision';
export interface ScheduleTaskType {
id?: number;
@@ -35,6 +39,14 @@ export interface TaskCallbacks {
onError?: (message: string) => Promise<void>;
}
function opaqueLegacyTaskId(
runOrigin: ScheduleTaskType['runOrigin'],
id: string,
): string {
const digest = createHash('sha256').update(id).digest('hex').slice(0, 25);
return `legacy-schedule:${runOrigin}:${digest}`;
}
@Service()
export default class ScheduleService {
private scheduleStacks = new Map<string, nodeSchedule.Job>();
@@ -76,7 +88,26 @@ export default class ScheduleService {
const startTime = dayjs();
await callbacks.onBefore?.(startTime);
const observation = observeLegacyExecution(runOrigin, () => {
const taskRevision = createLegacyTaskRevision({
command: others.command ?? command,
...(others.schedule === undefined
? {}
: { schedule: others.schedule }),
});
return {
origin: runOrigin,
projectId: 'default',
taskId: opaqueLegacyTaskId(runOrigin, others.id),
taskRevision,
...(others.name === undefined ? {} : { taskName: others.name }),
triggerType: runOrigin,
triggeredBy: 'legacy:schedule-service',
acceptedAtMs: Date.now(),
};
});
const cp = spawn(command, { shell: '/bin/bash' });
if (observation) observeLegacyChildProcess(cp, observation);
callbacks.onStart?.(cp, startTime);
completionTime === 'start' && resolve(cp.pid);