mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-08 20:28:29 +00:00
chore: migrate to oxlint and oxfmt
Co-authored-by: Christoph Nakazawa <christoph.pojer@gmail.com>
This commit is contained in:
@@ -12,9 +12,7 @@ import type { CronServiceState } from "./state.js";
|
||||
|
||||
const STUCK_RUN_MS = 2 * 60 * 60 * 1000;
|
||||
|
||||
export function assertSupportedJobSpec(
|
||||
job: Pick<CronJob, "sessionTarget" | "payload">,
|
||||
) {
|
||||
export function assertSupportedJobSpec(job: Pick<CronJob, "sessionTarget" | "payload">) {
|
||||
if (job.sessionTarget === "main" && job.payload.kind !== "systemEvent") {
|
||||
throw new Error('main cron jobs require payload.kind="systemEvent"');
|
||||
}
|
||||
@@ -29,15 +27,11 @@ export function findJobOrThrow(state: CronServiceState, id: string) {
|
||||
return job;
|
||||
}
|
||||
|
||||
export function computeJobNextRunAtMs(
|
||||
job: CronJob,
|
||||
nowMs: number,
|
||||
): number | undefined {
|
||||
export function computeJobNextRunAtMs(job: CronJob, nowMs: number): number | undefined {
|
||||
if (!job.enabled) return undefined;
|
||||
if (job.schedule.kind === "at") {
|
||||
// One-shot jobs stay due until they successfully finish.
|
||||
if (job.state.lastStatus === "ok" && job.state.lastRunAtMs)
|
||||
return undefined;
|
||||
if (job.state.lastStatus === "ok" && job.state.lastRunAtMs) return undefined;
|
||||
return job.schedule.atMs;
|
||||
}
|
||||
return computeNextRunAtMs(job.schedule, nowMs);
|
||||
@@ -67,9 +61,7 @@ export function recomputeNextRuns(state: CronServiceState) {
|
||||
|
||||
export function nextWakeAtMs(state: CronServiceState) {
|
||||
const jobs = state.store?.jobs ?? [];
|
||||
const enabled = jobs.filter(
|
||||
(j) => j.enabled && typeof j.state.nextRunAtMs === "number",
|
||||
);
|
||||
const enabled = jobs.filter((j) => j.enabled && typeof j.state.nextRunAtMs === "number");
|
||||
if (enabled.length === 0) return undefined;
|
||||
return enabled.reduce(
|
||||
(min, j) => Math.min(min, j.state.nextRunAtMs as number),
|
||||
@@ -77,10 +69,7 @@ export function nextWakeAtMs(state: CronServiceState) {
|
||||
);
|
||||
}
|
||||
|
||||
export function createJob(
|
||||
state: CronServiceState,
|
||||
input: CronJobCreate,
|
||||
): CronJob {
|
||||
export function createJob(state: CronServiceState, input: CronJobCreate): CronJob {
|
||||
const now = state.deps.nowMs();
|
||||
const id = crypto.randomUUID();
|
||||
const job: CronJob = {
|
||||
@@ -108,11 +97,9 @@ export function createJob(
|
||||
|
||||
export function applyJobPatch(job: CronJob, patch: CronJobPatch) {
|
||||
if ("name" in patch) job.name = normalizeRequiredName(patch.name);
|
||||
if ("description" in patch)
|
||||
job.description = normalizeOptionalText(patch.description);
|
||||
if ("description" in patch) job.description = normalizeOptionalText(patch.description);
|
||||
if (typeof patch.enabled === "boolean") job.enabled = patch.enabled;
|
||||
if (typeof patch.deleteAfterRun === "boolean")
|
||||
job.deleteAfterRun = patch.deleteAfterRun;
|
||||
if (typeof patch.deleteAfterRun === "boolean") job.deleteAfterRun = patch.deleteAfterRun;
|
||||
if (patch.schedule) job.schedule = patch.schedule;
|
||||
if (patch.sessionTarget) job.sessionTarget = patch.sessionTarget;
|
||||
if (patch.wakeMode) job.wakeMode = patch.wakeMode;
|
||||
@@ -120,24 +107,14 @@ export function applyJobPatch(job: CronJob, patch: CronJobPatch) {
|
||||
if (patch.isolation) job.isolation = patch.isolation;
|
||||
if (patch.state) job.state = { ...job.state, ...patch.state };
|
||||
if ("agentId" in patch) {
|
||||
job.agentId = normalizeOptionalAgentId(
|
||||
(patch as { agentId?: unknown }).agentId,
|
||||
);
|
||||
job.agentId = normalizeOptionalAgentId((patch as { agentId?: unknown }).agentId);
|
||||
}
|
||||
assertSupportedJobSpec(job);
|
||||
}
|
||||
|
||||
export function isJobDue(
|
||||
job: CronJob,
|
||||
nowMs: number,
|
||||
opts: { forced: boolean },
|
||||
) {
|
||||
export function isJobDue(job: CronJob, nowMs: number, opts: { forced: boolean }) {
|
||||
if (opts.forced) return true;
|
||||
return (
|
||||
job.enabled &&
|
||||
typeof job.state.nextRunAtMs === "number" &&
|
||||
nowMs >= job.state.nextRunAtMs
|
||||
);
|
||||
return job.enabled && typeof job.state.nextRunAtMs === "number" && nowMs >= job.state.nextRunAtMs;
|
||||
}
|
||||
|
||||
export function resolveJobPayloadTextForMain(job: CronJob): string | undefined {
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
import type { CronServiceState } from "./state.js";
|
||||
|
||||
export async function locked<T>(
|
||||
state: CronServiceState,
|
||||
fn: () => Promise<T>,
|
||||
): Promise<T> {
|
||||
export async function locked<T>(state: CronServiceState, fn: () => Promise<T>): Promise<T> {
|
||||
const next = state.op.then(fn, fn);
|
||||
// Keep the chain alive even when the operation fails.
|
||||
state.op = next.then(
|
||||
|
||||
@@ -34,8 +34,7 @@ export function inferLegacyName(job: {
|
||||
const text =
|
||||
job?.payload?.kind === "systemEvent" && typeof job.payload.text === "string"
|
||||
? job.payload.text
|
||||
: job?.payload?.kind === "agentTurn" &&
|
||||
typeof job.payload.message === "string"
|
||||
: job?.payload?.kind === "agentTurn" && typeof job.payload.message === "string"
|
||||
? job.payload.message
|
||||
: "";
|
||||
const firstLine =
|
||||
|
||||
@@ -45,25 +45,17 @@ export async function status(state: CronServiceState) {
|
||||
enabled: state.deps.cronEnabled,
|
||||
storePath: state.deps.storePath,
|
||||
jobs: state.store?.jobs.length ?? 0,
|
||||
nextWakeAtMs:
|
||||
state.deps.cronEnabled === true ? (nextWakeAtMs(state) ?? null) : null,
|
||||
nextWakeAtMs: state.deps.cronEnabled === true ? (nextWakeAtMs(state) ?? null) : null,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
export async function list(
|
||||
state: CronServiceState,
|
||||
opts?: { includeDisabled?: boolean },
|
||||
) {
|
||||
export async function list(state: CronServiceState, opts?: { includeDisabled?: boolean }) {
|
||||
return await locked(state, async () => {
|
||||
await ensureLoaded(state);
|
||||
const includeDisabled = opts?.includeDisabled === true;
|
||||
const jobs = (state.store?.jobs ?? []).filter(
|
||||
(j) => includeDisabled || j.enabled,
|
||||
);
|
||||
return jobs.sort(
|
||||
(a, b) => (a.state.nextRunAtMs ?? 0) - (b.state.nextRunAtMs ?? 0),
|
||||
);
|
||||
const jobs = (state.store?.jobs ?? []).filter((j) => includeDisabled || j.enabled);
|
||||
return jobs.sort((a, b) => (a.state.nextRunAtMs ?? 0) - (b.state.nextRunAtMs ?? 0));
|
||||
});
|
||||
}
|
||||
|
||||
@@ -84,11 +76,7 @@ export async function add(state: CronServiceState, input: CronJobCreate) {
|
||||
});
|
||||
}
|
||||
|
||||
export async function update(
|
||||
state: CronServiceState,
|
||||
id: string,
|
||||
patch: CronJobPatch,
|
||||
) {
|
||||
export async function update(state: CronServiceState, id: string, patch: CronJobPatch) {
|
||||
return await locked(state, async () => {
|
||||
warnIfDisabled(state, "update");
|
||||
await ensureLoaded(state);
|
||||
@@ -129,11 +117,7 @@ export async function remove(state: CronServiceState, id: string) {
|
||||
});
|
||||
}
|
||||
|
||||
export async function run(
|
||||
state: CronServiceState,
|
||||
id: string,
|
||||
mode?: "due" | "force",
|
||||
) {
|
||||
export async function run(state: CronServiceState, id: string, mode?: "due" | "force") {
|
||||
return await locked(state, async () => {
|
||||
warnIfDisabled(state, "run");
|
||||
await ensureLoaded(state);
|
||||
|
||||
@@ -1,10 +1,5 @@
|
||||
import type { HeartbeatRunResult } from "../../infra/heartbeat-wake.js";
|
||||
import type {
|
||||
CronJob,
|
||||
CronJobCreate,
|
||||
CronJobPatch,
|
||||
CronStoreFile,
|
||||
} from "../types.js";
|
||||
import type { CronJob, CronJobCreate, CronJobPatch, CronStoreFile } from "../types.js";
|
||||
|
||||
export type CronEvent = {
|
||||
jobId: string;
|
||||
@@ -31,9 +26,7 @@ export type CronServiceDeps = {
|
||||
cronEnabled: boolean;
|
||||
enqueueSystemEvent: (text: string, opts?: { agentId?: string }) => void;
|
||||
requestHeartbeatNow: (opts?: { reason?: string }) => void;
|
||||
runHeartbeatOnce?: (opts?: {
|
||||
reason?: string;
|
||||
}) => Promise<HeartbeatRunResult>;
|
||||
runHeartbeatOnce?: (opts?: { reason?: string }) => Promise<HeartbeatRunResult>;
|
||||
runIsolatedAgentJob: (params: { job: CronJob; message: string }) => Promise<{
|
||||
status: "ok" | "error" | "skipped";
|
||||
summary?: string;
|
||||
@@ -55,9 +48,7 @@ export type CronServiceState = {
|
||||
warnedDisabled: boolean;
|
||||
};
|
||||
|
||||
export function createCronServiceState(
|
||||
deps: CronServiceDeps,
|
||||
): CronServiceState {
|
||||
export function createCronServiceState(deps: CronServiceDeps): CronServiceState {
|
||||
return {
|
||||
deps: { ...deps, nowMs: deps.nowMs ?? (() => Date.now()) },
|
||||
store: null,
|
||||
@@ -83,9 +74,7 @@ export type CronRunResult =
|
||||
| { ok: true; ran: false; reason: "not-due" }
|
||||
| { ok: false };
|
||||
|
||||
export type CronRemoveResult =
|
||||
| { ok: true; removed: boolean }
|
||||
| { ok: false; removed: false };
|
||||
export type CronRemoveResult = { ok: true; removed: boolean } | { ok: false; removed: false };
|
||||
|
||||
export type CronAddResult = CronJob;
|
||||
export type CronUpdateResult = CronJob;
|
||||
|
||||
@@ -1,10 +1,6 @@
|
||||
import type { HeartbeatRunResult } from "../../infra/heartbeat-wake.js";
|
||||
import type { CronJob } from "../types.js";
|
||||
import {
|
||||
computeJobNextRunAtMs,
|
||||
nextWakeAtMs,
|
||||
resolveJobPayloadTextForMain,
|
||||
} from "./jobs.js";
|
||||
import { computeJobNextRunAtMs, nextWakeAtMs, resolveJobPayloadTextForMain } from "./jobs.js";
|
||||
import { locked } from "./locked.js";
|
||||
import type { CronEvent, CronServiceState } from "./state.js";
|
||||
import { ensureLoaded, persist } from "./store.js";
|
||||
@@ -70,11 +66,7 @@ export async function executeJob(
|
||||
|
||||
let deleted = false;
|
||||
|
||||
const finish = async (
|
||||
status: "ok" | "error" | "skipped",
|
||||
err?: string,
|
||||
summary?: string,
|
||||
) => {
|
||||
const finish = async (status: "ok" | "error" | "skipped", err?: string, summary?: string) => {
|
||||
const endedAt = state.deps.nowMs();
|
||||
job.state.runningAtMs = undefined;
|
||||
job.state.lastRunAtMs = startedAt;
|
||||
@@ -83,9 +75,7 @@ export async function executeJob(
|
||||
job.state.lastError = err;
|
||||
|
||||
const shouldDelete =
|
||||
job.schedule.kind === "at" &&
|
||||
status === "ok" &&
|
||||
job.deleteAfterRun === true;
|
||||
job.schedule.kind === "at" && status === "ok" && job.deleteAfterRun === true;
|
||||
|
||||
if (!shouldDelete) {
|
||||
if (job.schedule.kind === "at" && status === "ok") {
|
||||
@@ -145,8 +135,7 @@ export async function executeJob(
|
||||
state.deps.enqueueSystemEvent(text, { agentId: job.agentId });
|
||||
if (job.wakeMode === "now" && state.deps.runHeartbeatOnce) {
|
||||
const reason = `cron:${job.id}`;
|
||||
const delay = (ms: number) =>
|
||||
new Promise<void>((resolve) => setTimeout(resolve, ms));
|
||||
const delay = (ms: number) => new Promise<void>((resolve) => setTimeout(resolve, ms));
|
||||
const maxWaitMs = 2 * 60_000;
|
||||
const waitStartedAt = state.deps.nowMs();
|
||||
|
||||
@@ -194,8 +183,7 @@ export async function executeJob(
|
||||
message: job.payload.message,
|
||||
});
|
||||
if (res.status === "ok") await finish("ok", undefined, res.summary);
|
||||
else if (res.status === "skipped")
|
||||
await finish("skipped", undefined, res.summary);
|
||||
else if (res.status === "skipped") await finish("skipped", undefined, res.summary);
|
||||
else await finish("error", res.error ?? "cron job failed", res.summary);
|
||||
} catch (err) {
|
||||
await finish("error", String(err));
|
||||
|
||||
Reference in New Issue
Block a user