mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-09 14:24:30 +00:00
fix(cron): share isolated announce flow + harden cron scheduling/delivery (#11641)
* fix(cron): comprehensive cron scheduling and delivery fixes - Fix delivery target resolution for isolated agent cron jobs - Improve schedule parsing and validation - Add job retry logic and error handling - Enhance cron ops with better state management - Add timer improvements for more reliable cron execution - Add cron event type to protocol schema - Support cron events in heartbeat runner (skip empty-heartbeat check, use dedicated CRON_EVENT_PROMPT for relay) * fix: remove cron debug test and add changelog/docs notes (#11641) (thanks @tyler6204)
This commit is contained in:
@@ -52,6 +52,12 @@ export function stop(state: CronServiceState) {
|
||||
export async function status(state: CronServiceState) {
|
||||
return await locked(state, async () => {
|
||||
await ensureLoaded(state, { skipRecompute: true });
|
||||
if (state.store) {
|
||||
const changed = recomputeNextRuns(state);
|
||||
if (changed) {
|
||||
await persist(state);
|
||||
}
|
||||
}
|
||||
return {
|
||||
enabled: state.deps.cronEnabled,
|
||||
storePath: state.deps.storePath,
|
||||
@@ -64,6 +70,12 @@ export async function status(state: CronServiceState) {
|
||||
export async function list(state: CronServiceState, opts?: { includeDisabled?: boolean }) {
|
||||
return await locked(state, async () => {
|
||||
await ensureLoaded(state, { skipRecompute: true });
|
||||
if (state.store) {
|
||||
const changed = recomputeNextRuns(state);
|
||||
if (changed) {
|
||||
await persist(state);
|
||||
}
|
||||
}
|
||||
const includeDisabled = opts?.includeDisabled === true;
|
||||
const jobs = (state.store?.jobs ?? []).filter((j) => includeDisabled || j.enabled);
|
||||
return jobs.toSorted((a, b) => (a.state.nextRunAtMs ?? 0) - (b.state.nextRunAtMs ?? 0));
|
||||
@@ -76,8 +88,25 @@ export async function add(state: CronServiceState, input: CronJobCreate) {
|
||||
await ensureLoaded(state);
|
||||
const job = createJob(state, input);
|
||||
state.store?.jobs.push(job);
|
||||
|
||||
// Defensive: recompute all next-run times to ensure consistency
|
||||
recomputeNextRuns(state);
|
||||
|
||||
await persist(state);
|
||||
armTimer(state);
|
||||
|
||||
state.deps.log.info(
|
||||
{
|
||||
jobId: job.id,
|
||||
jobName: job.name,
|
||||
nextRunAtMs: job.state.nextRunAtMs,
|
||||
schedulerNextWakeAtMs: nextWakeAtMs(state) ?? null,
|
||||
timerArmed: state.timer !== null,
|
||||
cronEnabled: state.deps.cronEnabled,
|
||||
},
|
||||
"cron: job added",
|
||||
);
|
||||
|
||||
emit(state, {
|
||||
jobId: job.id,
|
||||
action: "added",
|
||||
@@ -110,12 +139,17 @@ export async function update(state: CronServiceState, id: string, patch: CronJob
|
||||
};
|
||||
}
|
||||
}
|
||||
const scheduleChanged = patch.schedule !== undefined;
|
||||
const enabledChanged = patch.enabled !== undefined;
|
||||
|
||||
job.updatedAtMs = now;
|
||||
if (job.enabled) {
|
||||
job.state.nextRunAtMs = computeJobNextRunAtMs(job, now);
|
||||
} else {
|
||||
job.state.nextRunAtMs = undefined;
|
||||
job.state.runningAtMs = undefined;
|
||||
if (scheduleChanged || enabledChanged) {
|
||||
if (job.enabled) {
|
||||
job.state.nextRunAtMs = computeJobNextRunAtMs(job, now);
|
||||
} else {
|
||||
job.state.nextRunAtMs = undefined;
|
||||
job.state.runningAtMs = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
await persist(state);
|
||||
|
||||
Reference in New Issue
Block a user