mirror of
https://github.com/openclaw/openclaw.git
synced 2026-03-17 13:00:48 +00:00
Previously, if one cron job had a malformed schedule expression (e.g. invalid cron syntax), the error would propagate up and break the entire scheduler loop. This meant one misconfigured job could prevent ALL cron jobs from running. Changes: - Wrap per-job schedule computation in try/catch in recomputeNextRuns() - Track consecutive schedule errors via new scheduleErrorCount field - Log warnings for schedule errors with job ID and name - Auto-disable jobs after 3 consecutive schedule errors (with error-level log) - Clear error count when schedule computation succeeds - Continue processing other jobs even when one fails This ensures the scheduler is resilient to individual job misconfigurations while still providing visibility into problems through logging. Co-authored-by: Marvin <numegilagent@gmail.com>
99 lines
2.6 KiB
TypeScript
99 lines
2.6 KiB
TypeScript
import type { ChannelId } from "../channels/plugins/types.js";
|
|
|
|
export type CronSchedule =
|
|
| { kind: "at"; at: string }
|
|
| { kind: "every"; everyMs: number; anchorMs?: number }
|
|
| { kind: "cron"; expr: string; tz?: string };
|
|
|
|
export type CronSessionTarget = "main" | "isolated";
|
|
export type CronWakeMode = "next-heartbeat" | "now";
|
|
|
|
export type CronMessageChannel = ChannelId | "last";
|
|
|
|
export type CronDeliveryMode = "none" | "announce";
|
|
|
|
export type CronDelivery = {
|
|
mode: CronDeliveryMode;
|
|
channel?: CronMessageChannel;
|
|
to?: string;
|
|
bestEffort?: boolean;
|
|
};
|
|
|
|
export type CronDeliveryPatch = Partial<CronDelivery>;
|
|
|
|
export type CronPayload =
|
|
| { kind: "systemEvent"; text: string }
|
|
| {
|
|
kind: "agentTurn";
|
|
message: string;
|
|
/** Optional model override (provider/model or alias). */
|
|
model?: string;
|
|
thinking?: string;
|
|
timeoutSeconds?: number;
|
|
allowUnsafeExternalContent?: boolean;
|
|
deliver?: boolean;
|
|
channel?: CronMessageChannel;
|
|
to?: string;
|
|
bestEffortDeliver?: boolean;
|
|
};
|
|
|
|
export type CronPayloadPatch =
|
|
| { kind: "systemEvent"; text?: string }
|
|
| {
|
|
kind: "agentTurn";
|
|
message?: string;
|
|
model?: string;
|
|
thinking?: string;
|
|
timeoutSeconds?: number;
|
|
allowUnsafeExternalContent?: boolean;
|
|
deliver?: boolean;
|
|
channel?: CronMessageChannel;
|
|
to?: string;
|
|
bestEffortDeliver?: boolean;
|
|
};
|
|
|
|
export type CronJobState = {
|
|
nextRunAtMs?: number;
|
|
runningAtMs?: number;
|
|
lastRunAtMs?: number;
|
|
lastStatus?: "ok" | "error" | "skipped";
|
|
lastError?: string;
|
|
lastDurationMs?: number;
|
|
/** Number of consecutive execution errors (reset on success). Used for backoff. */
|
|
consecutiveErrors?: number;
|
|
/** Number of consecutive schedule computation errors. Auto-disables job after threshold. */
|
|
scheduleErrorCount?: number;
|
|
};
|
|
|
|
export type CronJob = {
|
|
id: string;
|
|
agentId?: string;
|
|
name: string;
|
|
description?: string;
|
|
enabled: boolean;
|
|
deleteAfterRun?: boolean;
|
|
createdAtMs: number;
|
|
updatedAtMs: number;
|
|
schedule: CronSchedule;
|
|
sessionTarget: CronSessionTarget;
|
|
wakeMode: CronWakeMode;
|
|
payload: CronPayload;
|
|
delivery?: CronDelivery;
|
|
state: CronJobState;
|
|
};
|
|
|
|
export type CronStoreFile = {
|
|
version: 1;
|
|
jobs: CronJob[];
|
|
};
|
|
|
|
export type CronJobCreate = Omit<CronJob, "id" | "createdAtMs" | "updatedAtMs" | "state"> & {
|
|
state?: Partial<CronJobState>;
|
|
};
|
|
|
|
export type CronJobPatch = Partial<Omit<CronJob, "id" | "createdAtMs" | "state" | "payload">> & {
|
|
payload?: CronPayloadPatch;
|
|
delivery?: CronDeliveryPatch;
|
|
state?: Partial<CronJobState>;
|
|
};
|