fix(cron): split run and delivery status tracking

This commit is contained in:
Peter Steinberger
2026-02-22 20:07:34 +01:00
parent c3bb723673
commit aa4c250eb8
11 changed files with 128 additions and 13 deletions

View File

@@ -21,6 +21,17 @@ function cronAgentTurnPayloadSchema(params: { message: TSchema }) {
const CronSessionTargetSchema = Type.Union([Type.Literal("main"), Type.Literal("isolated")]);
const CronWakeModeSchema = Type.Union([Type.Literal("next-heartbeat"), Type.Literal("now")]);
const CronRunStatusSchema = Type.Union([
Type.Literal("ok"),
Type.Literal("error"),
Type.Literal("skipped"),
]);
const CronDeliveryStatusSchema = Type.Union([
Type.Literal("delivered"),
Type.Literal("not-delivered"),
Type.Literal("unknown"),
Type.Literal("not-requested"),
]);
const CronCommonOptionalFields = {
agentId: Type.Optional(Type.Union([NonEmptyString, Type.Null()])),
sessionKey: Type.Optional(Type.Union([NonEmptyString, Type.Null()])),
@@ -151,13 +162,14 @@ export const CronJobStateSchema = Type.Object(
nextRunAtMs: Type.Optional(Type.Integer({ minimum: 0 })),
runningAtMs: Type.Optional(Type.Integer({ minimum: 0 })),
lastRunAtMs: Type.Optional(Type.Integer({ minimum: 0 })),
lastStatus: Type.Optional(
Type.Union([Type.Literal("ok"), Type.Literal("error"), Type.Literal("skipped")]),
),
lastRunStatus: Type.Optional(CronRunStatusSchema),
lastStatus: Type.Optional(CronRunStatusSchema),
lastError: Type.Optional(Type.String()),
lastDurationMs: Type.Optional(Type.Integer({ minimum: 0 })),
consecutiveErrors: Type.Optional(Type.Integer({ minimum: 0 })),
lastDelivered: Type.Optional(Type.Boolean()),
lastDeliveryStatus: Type.Optional(CronDeliveryStatusSchema),
lastDeliveryError: Type.Optional(Type.String()),
},
{ additionalProperties: false },
);
@@ -238,11 +250,12 @@ export const CronRunLogEntrySchema = Type.Object(
ts: Type.Integer({ minimum: 0 }),
jobId: NonEmptyString,
action: Type.Literal("finished"),
status: Type.Optional(
Type.Union([Type.Literal("ok"), Type.Literal("error"), Type.Literal("skipped")]),
),
status: Type.Optional(CronRunStatusSchema),
error: Type.Optional(Type.String()),
summary: Type.Optional(Type.String()),
delivered: Type.Optional(Type.Boolean()),
deliveryStatus: Type.Optional(CronDeliveryStatusSchema),
deliveryError: Type.Optional(Type.String()),
sessionId: Type.Optional(NonEmptyString),
sessionKey: Type.Optional(NonEmptyString),
runAtMs: Type.Optional(Type.Integer({ minimum: 0 })),

View File

@@ -297,6 +297,8 @@ export function buildGatewayCronService(params: {
error: evt.error,
summary: evt.summary,
delivered: evt.delivered,
deliveryStatus: evt.deliveryStatus,
deliveryError: evt.deliveryError,
sessionId: evt.sessionId,
sessionKey: evt.sessionKey,
runAtMs: evt.runAtMs,

View File

@@ -407,11 +407,13 @@ describe("gateway server cron", () => {
action?: unknown;
status?: unknown;
summary?: unknown;
deliveryStatus?: unknown;
};
expect(last.action).toBe("finished");
expect(last.jobId).toBe(jobId);
expect(last.status).toBe("ok");
expect(last.summary).toBe("hello");
expect(last.deliveryStatus).toBe("not-requested");
const runsRes = await rpcReq(ws, "cron.runs", { id: jobId, limit: 50 });
expect(runsRes.ok).toBe(true);
@@ -419,6 +421,9 @@ describe("gateway server cron", () => {
expect(Array.isArray(entries)).toBe(true);
expect((entries as Array<{ jobId?: unknown }>).at(-1)?.jobId).toBe(jobId);
expect((entries as Array<{ summary?: unknown }>).at(-1)?.summary).toBe("hello");
expect((entries as Array<{ deliveryStatus?: unknown }>).at(-1)?.deliveryStatus).toBe(
"not-requested",
);
const statusRes = await rpcReq(ws, "cron.status", {});
expect(statusRes.ok).toBe(true);