






















@@ -2,7 +2,7 @@ import { resolveFailoverReasonFromError } from "../../agents/failover-error.js";
22import { formatEmbeddedAgentExecutionPhase } from "../../agents/pi-embedded-runner/execution-phase.js";
33import { readSessionEntry } from "../../config/sessions/store-load.js";
44import type { SessionEntry } from "../../config/sessions/types.js";
5-import type { CronConfig, CronRetryOn } from "../../config/types.cron.js";
5+import type { CronConfig } from "../../config/types.cron.js";
66import type { HeartbeatRunResult } from "../../infra/heartbeat-wake.js";
77import {
88HEARTBEAT_SKIP_CRON_IN_PROGRESS,
@@ -25,6 +25,7 @@ import type { DeliveryContext } from "../../utils/delivery-context.types.js";
2525import { clearCronJobActive, markCronJobActive } from "../active-jobs.js";
2626import { resolveCronDeliveryPlan, resolveFailureDestination } from "../delivery-plan.js";
2727import { resolveCronAgentSessionKey } from "../isolated-agent/session-key.js";
28+import { resolveCronExecutionRetryHint } from "../retry-hint.js";
2829import {
2930createCronRunDiagnosticsFromError,
3031normalizeCronRunDiagnostics,
@@ -560,28 +561,6 @@ function tryFinishCronTaskRun(
560561/** Default max retries for one-shot jobs on transient errors (#24355). */
561562const DEFAULT_MAX_TRANSIENT_RETRIES = 3;
562563563-const TRANSIENT_PATTERNS: Record<string, RegExp> = {
564-rate_limit:
565-/(rate[_ ]limit|too many requests|429|resource has been exhausted|cloudflare|tokens per day)/i,
566-overloaded:
567-/\b529\b|\boverloaded(?:_error)?\b|high demand|temporar(?:ily|y) overloaded|capacity exceeded/i,
568-network: /(network|econnreset|econnrefused|fetch failed|socket)/i,
569-timeout: /(timeout|etimedout)/i,
570-server_error: /\b5\d{2}\b/,
571-};
572-573-function isTransientCronError(error: string | undefined, retryOn?: CronRetryOn[]): boolean {
574-if (!error || typeof error !== "string") {
575-return false;
576-}
577-const keys = retryOn?.length ? retryOn : (Object.keys(TRANSIENT_PATTERNS) as CronRetryOn[]);
578-const classified = resolveFailoverReasonFromError(error);
579-if (classified && keys.includes(classified as CronRetryOn)) {
580-return true;
581-}
582-return keys.some((k) => TRANSIENT_PATTERNS[k]?.test(error));
583-}
584-585564function resolveCronNextRunWithLowerBound(params: {
586565state: CronServiceState;
587566job: CronJob;
@@ -970,10 +949,14 @@ export function applyJobResult(
970949job.state.nextRunAtMs = undefined;
971950} else if (result.status === "error") {
972951const retryConfig = resolveRetryConfig(state.deps.cronConfig);
973-const transient = isTransientCronError(result.error, retryConfig.retryOn);
952+const retryHint = resolveCronExecutionRetryHint(
953+result.error,
954+retryConfig.retryOn,
955+job.state.lastErrorReason,
956+);
974957// consecutiveErrors is always set to ≥1 by the increment block above.
975958const consecutive = job.state.consecutiveErrors;
976-if (transient && consecutive <= retryConfig.maxAttempts) {
959+if (retryHint.retryable && consecutive <= retryConfig.maxAttempts) {
977960// Schedule retry with backoff (#24355).
978961const backoff = errorBackoffMs(consecutive, retryConfig.backoffMs);
979962job.state.nextRunAtMs = result.endedAt + backoff;
@@ -1000,7 +983,8 @@ export function applyJobResult(
1000983jobName: job.name,
1001984consecutiveErrors: consecutive,
1002985error: result.error,
1003-reason: transient ? "max retries exhausted" : "permanent error",
986+reason: retryHint.retryable ? "max retries exhausted" : "permanent error",
987+retryCategory: retryHint.category,
1004988},
1005989"cron: disabling one-shot job after error",
1006990);
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。