diff --git a/spec/runtime/manifest.spec.ts b/spec/runtime/manifest.spec.ts index 7534ba2ee..8f520a210 100644 --- a/spec/runtime/manifest.spec.ts +++ b/spec/runtime/manifest.spec.ts @@ -286,6 +286,7 @@ describe("initScheduleTrigger", () => { expect(st).to.deep.eq({ schedule: "every 30 minutes", timeZone: RESET_VALUE, + attemptDeadlineSeconds: RESET_VALUE, retryConfig: { retryCount: RESET_VALUE, maxDoublings: RESET_VALUE, diff --git a/spec/v2/providers/scheduler.spec.ts b/spec/v2/providers/scheduler.spec.ts index fcd03cf1f..983e2f761 100644 --- a/spec/v2/providers/scheduler.spec.ts +++ b/spec/v2/providers/scheduler.spec.ts @@ -32,6 +32,7 @@ import { runHandler } from "../../helper"; const MINIMAL_SCHEDULE_TRIGGER: ManifestEndpoint["scheduleTrigger"] = { schedule: "", timeZone: options.RESET_VALUE, + attemptDeadlineSeconds: options.RESET_VALUE, retryConfig: { retryCount: options.RESET_VALUE, maxRetrySeconds: options.RESET_VALUE, @@ -66,6 +67,7 @@ describe("schedule", () => { expect(schedule.getOpts(options)).to.deep.eq({ schedule: "* * * * *", timeZone: "utc", + attemptDeadlineSeconds: undefined, retryConfig: { retryCount: 3, maxRetrySeconds: 1, @@ -108,6 +110,7 @@ describe("schedule", () => { { schedule: "* * * * *", timeZone: "utc", + attemptDeadlineSeconds: 300, retryCount: 3, maxRetrySeconds: 10, minBackoffSeconds: 11, @@ -127,6 +130,7 @@ describe("schedule", () => { scheduleTrigger: { schedule: "* * * * *", timeZone: "utc", + attemptDeadlineSeconds: 300, retryConfig: { retryCount: 3, maxRetrySeconds: 10, @@ -159,6 +163,7 @@ describe("schedule", () => { scheduleTrigger: { schedule: "* * * * *", timeZone: undefined, + attemptDeadlineSeconds: undefined, retryConfig: { retryCount: undefined, maxRetrySeconds: undefined, diff --git a/src/runtime/manifest.ts b/src/runtime/manifest.ts index 4d52d5eaf..e2c66c0ba 100644 --- a/src/runtime/manifest.ts +++ b/src/runtime/manifest.ts @@ -97,6 +97,7 @@ export interface ManifestEndpoint { scheduleTrigger?: { schedule: string | Expression; timeZone?: string | Expression | ResetValue; + attemptDeadlineSeconds?: number | Expression | ResetValue; retryConfig?: { retryCount?: number | Expression | ResetValue; maxRetrySeconds?: string | Expression | ResetValue; @@ -259,12 +260,14 @@ const RESETTABLE_V1_SCHEDULE_OPTIONS: Omit< const RESETTABLE_V2_SCHEDULE_OPTIONS: Omit< ResettableKeys, "maxRetryDuration" | "maxBackoffDuration" | "minBackoffDuration" -> = { +> & + Pick, "attemptDeadlineSeconds"> = { retryCount: null, maxDoublings: null, maxRetrySeconds: null, minBackoffSeconds: null, maxBackoffSeconds: null, + attemptDeadlineSeconds: null, }; function initScheduleTrigger( @@ -278,7 +281,11 @@ function initScheduleTrigger( }; if (opts.every((opt) => !opt?.preserveExternalChanges)) { for (const key of Object.keys(resetOptions)) { - scheduleTrigger.retryConfig[key] = RESET_VALUE; + if (key === "attemptDeadlineSeconds") { + scheduleTrigger[key] = RESET_VALUE; + } else { + scheduleTrigger.retryConfig[key] = RESET_VALUE; + } } scheduleTrigger = { ...scheduleTrigger, timeZone: RESET_VALUE }; } diff --git a/src/v2/providers/scheduler.ts b/src/v2/providers/scheduler.ts index 1f8f33c31..3b0af111f 100644 --- a/src/v2/providers/scheduler.ts +++ b/src/v2/providers/scheduler.ts @@ -42,6 +42,7 @@ import { withInit } from "../../common/onInit"; interface SeparatedOpts { schedule: string | Expression; timeZone?: timezone | Expression | ResetValue; + attemptDeadlineSeconds?: number | Expression | ResetValue; retryConfig?: { retryCount?: number | Expression | ResetValue; maxRetrySeconds?: number | Expression | ResetValue; @@ -63,6 +64,7 @@ export function getOpts(args: string | ScheduleOptions): SeparatedOpts { return { schedule: args.schedule, timeZone: args.timeZone, + attemptDeadlineSeconds: args.attemptDeadlineSeconds, retryConfig: { retryCount: args.retryCount, maxRetrySeconds: args.maxRetrySeconds, @@ -111,6 +113,13 @@ export interface ScheduleOptions extends options.GlobalOptions { /** The timezone that the schedule executes in. */ timeZone?: timezone | Expression | ResetValue; + /** + * The deadline for job attempts in seconds. If the request handler does not respond by this deadline, + * the request is cancelled and the attempt is marked as a `DEADLINE_EXCEEDED` failure. + * The value must be between 15 and 1800. Defaults to 180. + */ + attemptDeadlineSeconds?: number | Expression | ResetValue; + /** The number of retry attempts for a failed run. */ retryCount?: number | Expression | ResetValue; @@ -196,7 +205,7 @@ export function onSchedule( scheduleTrigger: initV2ScheduleTrigger(separatedOpts.schedule, globalOpts, separatedOpts.opts), }; - copyIfPresent(ep.scheduleTrigger, separatedOpts, "timeZone"); + copyIfPresent(ep.scheduleTrigger, separatedOpts, "timeZone", "attemptDeadlineSeconds"); copyIfPresent( ep.scheduleTrigger.retryConfig, separatedOpts.retryConfig,