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

@@ -309,6 +309,8 @@ export async function run(state: CronServiceState, id: string, mode?: "due" | "f
error: coreResult.error,
summary: coreResult.summary,
delivered: coreResult.delivered,
deliveryStatus: job.state.lastDeliveryStatus,
deliveryError: job.state.lastDeliveryError,
sessionId: coreResult.sessionId,
sessionKey: coreResult.sessionKey,
runAtMs: prepared.startedAt,

View File

@@ -1,6 +1,7 @@
import type { CronConfig } from "../../config/types.cron.js";
import type { HeartbeatRunResult } from "../../infra/heartbeat-wake.js";
import type {
CronDeliveryStatus,
CronJob,
CronJobCreate,
CronJobPatch,
@@ -19,6 +20,8 @@ export type CronEvent = {
error?: string;
summary?: string;
delivered?: boolean;
deliveryStatus?: CronDeliveryStatus;
deliveryError?: string;
sessionId?: string;
sessionKey?: string;
nextRunAtMs?: number;

View File

@@ -2,7 +2,13 @@ import type { HeartbeatRunResult } from "../../infra/heartbeat-wake.js";
import { DEFAULT_AGENT_ID } from "../../routing/session-key.js";
import { resolveCronDeliveryPlan } from "../delivery.js";
import { sweepCronRunSessions } from "../session-reaper.js";
import type { CronJob, CronRunOutcome, CronRunStatus, CronRunTelemetry } from "../types.js";
import type {
CronDeliveryStatus,
CronJob,
CronRunOutcome,
CronRunStatus,
CronRunTelemetry,
} from "../types.js";
import {
computeJobNextRunAtMs,
nextWakeAtMs,
@@ -63,6 +69,16 @@ function errorBackoffMs(consecutiveErrors: number): number {
return ERROR_BACKOFF_SCHEDULE_MS[Math.max(0, idx)];
}
function resolveDeliveryStatus(params: { job: CronJob; delivered?: boolean }): CronDeliveryStatus {
if (params.delivered === true) {
return "delivered";
}
if (params.delivered === false) {
return "not-delivered";
}
return resolveCronDeliveryPlan(params.job).requested ? "unknown" : "not-requested";
}
/**
* Apply the result of a job execution to the job's state.
* Handles consecutive error tracking, exponential backoff, one-shot disable,
@@ -81,10 +97,15 @@ export function applyJobResult(
): boolean {
job.state.runningAtMs = undefined;
job.state.lastRunAtMs = result.startedAt;
job.state.lastRunStatus = result.status;
job.state.lastStatus = result.status;
job.state.lastDurationMs = Math.max(0, result.endedAt - result.startedAt);
job.state.lastError = result.error;
job.state.lastDelivered = result.delivered;
const deliveryStatus = resolveDeliveryStatus({ job, delivered: result.delivered });
job.state.lastDeliveryStatus = deliveryStatus;
job.state.lastDeliveryError =
deliveryStatus === "not-delivered" && result.error ? result.error : undefined;
job.updatedAtMs = result.endedAt;
// Track consecutive errors for backoff / auto-disable.
@@ -748,6 +769,8 @@ function emitJobFinished(
error: result.error,
summary: result.summary,
delivered: result.delivered,
deliveryStatus: job.state.lastDeliveryStatus,
deliveryError: job.state.lastDeliveryError,
sessionId: result.sessionId,
sessionKey: result.sessionKey,
runAtMs,