Skip to content

Commit 047785e

Browse files
authored
fix(cron): report SQLite storage path in cron.status instead of legacy jobs.json (#92144)
* fix(cron): report SQLite storage path in cron.status instead of legacy jobs.json The `cron.status` gateway response returned `storePath` pointing to the legacy `jobs.json` path, but cron jobs are actually stored in the shared SQLite state database. This misled operators and agents into looking for a JSON file that no longer exists. - Add `storage: "sqlite"` and `sqlitePath` fields to CronStatusSummary - Mark legacy `storePath` as @deprecated (kept for backward compat) - Update CLI warning to prefer sqlitePath over storePath - Add regression assertions in read-ops test Fixes #91766 * fix(macos): prefer sqlitePath in cron status display * fix(macos): add sqlitePath to CronSchedulerStatus type
1 parent f7ee252 commit 047785e

7 files changed

Lines changed: 19 additions & 2 deletions

File tree

apps/macos/Sources/OpenClaw/CronJobsStore.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ final class CronJobsStore {
7272
do {
7373
if let status = try? await GatewayConnection.shared.cronStatus() {
7474
self.schedulerEnabled = status.enabled
75-
self.schedulerStorePath = status.storePath
75+
self.schedulerStorePath = status.sqlitePath ?? status.storePath
7676
self.schedulerNextWakeAtMs = status.nextWakeAtMs
7777
}
7878
self.jobs = try await GatewayConnection.shared.cronList(includeDisabled: true)

apps/macos/Sources/OpenClaw/GatewayConnection.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -775,6 +775,7 @@ extension GatewayConnection {
775775
struct CronSchedulerStatus: Decodable {
776776
let enabled: Bool
777777
let storePath: String
778+
let sqlitePath: String?
778779
let jobs: Int
779780
let nextWakeAtMs: Int?
780781
}

src/cli/cron-cli/shared.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -176,11 +176,15 @@ export async function warnIfCronSchedulerDisabled(opts: GatewayRpcOpts) {
176176
const res = (await callGatewayFromCli("cron.status", opts, {})) as {
177177
enabled?: boolean;
178178
storePath?: string;
179+
storage?: string;
180+
sqlitePath?: string;
179181
};
180182
if (res?.enabled === true) {
181183
return;
182184
}
183-
const store = typeof res?.storePath === "string" ? res.storePath : "";
185+
const store = typeof res?.sqlitePath === "string" ? res.sqlitePath
186+
: typeof res?.storePath === "string" ? res.storePath
187+
: "";
184188
defaultRuntime.error(
185189
[
186190
"warning: cron scheduler is disabled in the Gateway; jobs are saved but will not run automatically.",

src/cron/service.read-ops-nonblocking.test.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,8 @@ function expectCronStatus(
8383
) {
8484
expect(status.enabled).toBe(true);
8585
expect(status.storePath).toBe(params.storePath);
86+
expect(status.storage).toBe("sqlite");
87+
expect(status.sqlitePath).toContain("openclaw.sqlite");
8688
expect(status.jobs).toBe(params.jobs);
8789
if (status.nextWakeAtMs !== null) {
8890
expect(status.nextWakeAtMs).toBeTypeOf("number");

src/cron/service/ops.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { normalizeLowercaseStringOrEmpty } from "@openclaw/normalization-core/st
33
import { enqueueCommandInLane } from "../../process/command-queue.js";
44
import { CommandLane } from "../../process/lanes.js";
55
import { DEFAULT_AGENT_ID } from "../../routing/session-key.js";
6+
import { resolveOpenClawStateSqlitePath } from "../../state/openclaw-state-db.paths.js";
67
import {
78
completeTaskRunByRunId,
89
createRunningTaskRun,
@@ -254,6 +255,8 @@ export async function status(state: CronServiceState) {
254255
return {
255256
enabled: state.deps.cronEnabled,
256257
storePath: state.deps.storePath,
258+
storage: "sqlite" as const,
259+
sqlitePath: resolveOpenClawStateSqlitePath(),
257260
jobs: state.store?.jobs.length ?? 0,
258261
nextWakeAtMs: state.deps.cronEnabled ? (nextWakeAtMs(state) ?? null) : null,
259262
};

src/cron/service/state.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,7 +218,12 @@ export type CronWakeMode = "now" | "next-heartbeat";
218218
/** Lightweight service status returned to gateway/control surfaces. */
219219
export type CronStatusSummary = {
220220
enabled: boolean;
221+
/** @deprecated Legacy partition key; actual storage is SQLite. Use `sqlitePath`. */
221222
storePath: string;
223+
/** Storage backend identifier. */
224+
storage: "sqlite";
225+
/** Resolved path to the shared state SQLite database. */
226+
sqlitePath: string;
222227
jobs: number;
223228
nextWakeAtMs: number | null;
224229
};

src/plugins/contracts/scheduled-turns.contract.test.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,8 @@ function createMockCronService(): CronServiceContract {
9292
status: vi.fn(async () => ({
9393
enabled: true,
9494
storePath: "/tmp/openclaw-test-cron.json",
95+
storage: "sqlite" as const,
96+
sqlitePath: "/tmp/openclaw-test-state/state/openclaw.sqlite",
9597
jobs: 0,
9698
nextWakeAtMs: null,
9799
})),

0 commit comments

Comments
 (0)