From 33f9cad308dd51bf26342b0ce8596b472a521162 Mon Sep 17 00:00:00 2001 From: skyfury2651 Date: Tue, 19 Aug 2025 23:41:51 +0700 Subject: [PATCH 1/3] feat(scheduler): add support for attemptDeadline in onSchedule --- spec/runtime/manifest.spec.ts | 2 ++ spec/v1/cloud-functions.spec.ts | 1 + spec/v1/providers/fixtures.ts | 1 + spec/v1/providers/pubsub.spec.ts | 20 +++++++++++++++---- spec/v2/providers/scheduler.spec.ts | 16 +++++++++++++++ src/runtime/manifest.ts | 3 +++ src/v1/cloud-functions.ts | 3 ++- src/v1/function-configuration.ts | 5 +++++ src/v2/providers/scheduler.ts | 30 +++++++++++++++++++++-------- 9 files changed, 68 insertions(+), 13 deletions(-) diff --git a/spec/runtime/manifest.spec.ts b/spec/runtime/manifest.spec.ts index 7534ba2ee..7a1b5ee79 100644 --- a/spec/runtime/manifest.spec.ts +++ b/spec/runtime/manifest.spec.ts @@ -265,6 +265,7 @@ describe("initScheduleTrigger", () => { maxRetryDuration: RESET_VALUE, minBackoffDuration: RESET_VALUE, maxBackoffDuration: RESET_VALUE, + attemptDeadline: RESET_VALUE, }, }); }); @@ -292,6 +293,7 @@ describe("initScheduleTrigger", () => { maxRetrySeconds: RESET_VALUE, minBackoffSeconds: RESET_VALUE, maxBackoffSeconds: RESET_VALUE, + attemptDeadline: RESET_VALUE, }, }); }); diff --git a/spec/v1/cloud-functions.spec.ts b/spec/v1/cloud-functions.spec.ts index d85afbe2f..e17fd813e 100644 --- a/spec/v1/cloud-functions.spec.ts +++ b/spec/v1/cloud-functions.spec.ts @@ -212,6 +212,7 @@ describe("makeCloudFunction", () => { maxDoublings: RESET_VALUE, maxRetryDuration: RESET_VALUE, minBackoffDuration: RESET_VALUE, + attemptDeadline: RESET_VALUE, }, }, labels: {}, diff --git a/spec/v1/providers/fixtures.ts b/spec/v1/providers/fixtures.ts index e047ba07f..d15246851 100644 --- a/spec/v1/providers/fixtures.ts +++ b/spec/v1/providers/fixtures.ts @@ -46,5 +46,6 @@ export const MINIMAL_SCHEDULE_TRIGGER: ManifestEndpoint["scheduleTrigger"] = { maxBackoffDuration: options.RESET_VALUE, minBackoffDuration: options.RESET_VALUE, maxDoublings: options.RESET_VALUE, + attemptDeadline: options.RESET_VALUE, }, }; diff --git a/spec/v1/providers/pubsub.spec.ts b/spec/v1/providers/pubsub.spec.ts index 0a7b89ad6..3d0f41d2c 100644 --- a/spec/v1/providers/pubsub.spec.ts +++ b/spec/v1/providers/pubsub.spec.ts @@ -215,7 +215,10 @@ describe("Pubsub Functions", () => { expect(result.__endpoint.scheduleTrigger).to.deep.equal({ ...MINIMAL_SCHEDULE_TRIGGER, schedule: "every 5 minutes", - retryConfig, + retryConfig: { + ...retryConfig, + attemptDeadline: RESET_VALUE, + }, }); expect(result.__endpoint.labels).to.be.empty; }); @@ -249,7 +252,10 @@ describe("Pubsub Functions", () => { expect(result.__endpoint.scheduleTrigger).to.deep.equal({ ...MINIMAL_SCHEDULE_TRIGGER, schedule: "every 5 minutes", - retryConfig, + retryConfig: { + ...retryConfig, + attemptDeadline: RESET_VALUE, + }, timeZone: "America/New_York", }); expect(result.__endpoint.labels).to.be.empty; @@ -341,7 +347,10 @@ describe("Pubsub Functions", () => { ...MINIMAL_SCHEDULE_TRIGGER, schedule: "every 5 minutes", timeZone: RESET_VALUE, - retryConfig, + retryConfig: { + ...retryConfig, + attemptDeadline: RESET_VALUE, + }, }); expect(result.__endpoint.region).to.deep.equal(["us-east1"]); expect(result.__endpoint.availableMemoryMb).to.deep.equal(256); @@ -382,7 +391,10 @@ describe("Pubsub Functions", () => { ...MINIMAL_SCHEDULE_TRIGGER, schedule: "every 5 minutes", timeZone: "America/New_York", - retryConfig, + retryConfig: { + ...retryConfig, + attemptDeadline: RESET_VALUE, + }, }); expect(result.__endpoint.region).to.deep.equal(["us-east1"]); expect(result.__endpoint.availableMemoryMb).to.deep.equal(256); diff --git a/spec/v2/providers/scheduler.spec.ts b/spec/v2/providers/scheduler.spec.ts index fcd03cf1f..a65417300 100644 --- a/spec/v2/providers/scheduler.spec.ts +++ b/spec/v2/providers/scheduler.spec.ts @@ -38,6 +38,7 @@ const MINIMAL_SCHEDULE_TRIGGER: ManifestEndpoint["scheduleTrigger"] = { minBackoffSeconds: options.RESET_VALUE, maxBackoffSeconds: options.RESET_VALUE, maxDoublings: options.RESET_VALUE, + attemptDeadline: options.RESET_VALUE, }, }; @@ -103,6 +104,20 @@ describe("schedule", () => { ]); }); + it("should create a schedule function with attemptDeadline", () => { + const schfn = schedule.onSchedule( + { + schedule: "* * * * *", + attemptDeadline: "320s", + }, + () => undefined + ); + + expect(schfn.__endpoint.scheduleTrigger?.retryConfig?.attemptDeadline).to.equal( + "320s" + ); + }); + it("should create a schedule function given options", () => { const schfn = schedule.onSchedule( { @@ -133,6 +148,7 @@ describe("schedule", () => { minBackoffSeconds: 11, maxBackoffSeconds: 12, maxDoublings: 2, + attemptDeadline: options.RESET_VALUE, }, }, }); diff --git a/src/runtime/manifest.ts b/src/runtime/manifest.ts index 4d52d5eaf..235517dfc 100644 --- a/src/runtime/manifest.ts +++ b/src/runtime/manifest.ts @@ -107,6 +107,7 @@ export interface ManifestEndpoint { maxRetryDuration?: string | Expression | ResetValue; minBackoffDuration?: string | Expression | ResetValue; maxBackoffDuration?: string | Expression | ResetValue; + attemptDeadline?: string | Expression | ResetValue; }; }; @@ -254,6 +255,7 @@ const RESETTABLE_V1_SCHEDULE_OPTIONS: Omit< maxRetryDuration: null, maxBackoffDuration: null, minBackoffDuration: null, + attemptDeadline: null, }; const RESETTABLE_V2_SCHEDULE_OPTIONS: Omit< @@ -265,6 +267,7 @@ const RESETTABLE_V2_SCHEDULE_OPTIONS: Omit< maxRetrySeconds: null, minBackoffSeconds: null, maxBackoffSeconds: null, + attemptDeadline: null, }; function initScheduleTrigger( diff --git a/src/v1/cloud-functions.ts b/src/v1/cloud-functions.ts index 0a86853f9..bc4434d1d 100644 --- a/src/v1/cloud-functions.ts +++ b/src/v1/cloud-functions.ts @@ -485,7 +485,8 @@ export function makeCloudFunction({ "maxDoublings", "maxBackoffDuration", "maxRetryDuration", - "minBackoffDuration" + "minBackoffDuration", + "attemptDeadline" ); } else { endpoint.eventTrigger = { diff --git a/src/v1/function-configuration.ts b/src/v1/function-configuration.ts index 90aa391fc..b40b33a6c 100644 --- a/src/v1/function-configuration.ts +++ b/src/v1/function-configuration.ts @@ -110,6 +110,11 @@ export interface ScheduleRetryConfig { * @defaultValue 5 */ maxDoublings?: number | Expression | ResetValue; + + /** + * The deadline for each job attempt, specified as a duration string (e.g. "600s"). + */ + attemptDeadline?: string | Expression | ResetValue; } /** diff --git a/src/v2/providers/scheduler.ts b/src/v2/providers/scheduler.ts index 1f8f33c31..452e0a6e6 100644 --- a/src/v2/providers/scheduler.ts +++ b/src/v2/providers/scheduler.ts @@ -48,6 +48,7 @@ interface SeparatedOpts { minBackoffSeconds?: number | Expression | ResetValue; maxBackoffSeconds?: number | Expression | ResetValue; maxDoublings?: number | Expression | ResetValue; + attemptDeadline?: string | Expression | ResetValue; }; opts: options.GlobalOptions; } @@ -60,16 +61,22 @@ export function getOpts(args: string | ScheduleOptions): SeparatedOpts { opts: {} as options.GlobalOptions, }; } + const retryConfig: any = { + retryCount: args.retryCount, + maxRetrySeconds: args.maxRetrySeconds, + minBackoffSeconds: args.minBackoffSeconds, + maxBackoffSeconds: args.maxBackoffSeconds, + maxDoublings: args.maxDoublings, + }; + + if (args.attemptDeadline !== undefined) { + retryConfig.attemptDeadline = args.attemptDeadline; + } + return { schedule: args.schedule, timeZone: args.timeZone, - retryConfig: { - retryCount: args.retryCount, - maxRetrySeconds: args.maxRetrySeconds, - minBackoffSeconds: args.minBackoffSeconds, - maxBackoffSeconds: args.maxBackoffSeconds, - maxDoublings: args.maxDoublings, - }, + retryConfig, opts: args as options.GlobalOptions, }; } @@ -125,6 +132,12 @@ export interface ScheduleOptions extends options.GlobalOptions { /** The time between will double max doublings times. */ maxDoublings?: number | Expression | ResetValue; + + /** + * The deadline for each job attempt, specified as a duration string (e.g. "600s"). + * See: https://cloud.google.com/scheduler/docs/reference/rest/v1/projects.locations.jobs#Job + */ + attemptDeadline?: string | Expression | ResetValue; } /** @@ -204,7 +217,8 @@ export function onSchedule( "maxRetrySeconds", "minBackoffSeconds", "maxBackoffSeconds", - "maxDoublings" + "maxDoublings", + "attemptDeadline" ); func.__endpoint = ep; From d20a80f7176c784f42bbcd40e078128a34aeb54e Mon Sep 17 00:00:00 2001 From: skyfury2651 Date: Wed, 20 Aug 2025 00:02:35 +0700 Subject: [PATCH 2/3] refactor: update other full options testcase --- spec/v2/providers/scheduler.spec.ts | 6 +++++- src/v2/providers/scheduler.ts | 20 ++++++++------------ 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/spec/v2/providers/scheduler.spec.ts b/spec/v2/providers/scheduler.spec.ts index a65417300..b3fd04daa 100644 --- a/spec/v2/providers/scheduler.spec.ts +++ b/spec/v2/providers/scheduler.spec.ts @@ -60,6 +60,7 @@ describe("schedule", () => { minBackoffSeconds: 2, maxBackoffSeconds: 3, maxDoublings: 4, + attemptDeadline: "120s", memory: "128MiB", region: "us-central1", }; @@ -73,6 +74,7 @@ describe("schedule", () => { minBackoffSeconds: 2, maxBackoffSeconds: 3, maxDoublings: 4, + attemptDeadline: "120s", }, opts: { ...options, @@ -128,6 +130,7 @@ describe("schedule", () => { minBackoffSeconds: 11, maxBackoffSeconds: 12, maxDoublings: 2, + attemptDeadline: "120s", region: "us-central1", labels: { key: "val" }, }, @@ -148,7 +151,7 @@ describe("schedule", () => { minBackoffSeconds: 11, maxBackoffSeconds: 12, maxDoublings: 2, - attemptDeadline: options.RESET_VALUE, + attemptDeadline: "120s", }, }, }); @@ -181,6 +184,7 @@ describe("schedule", () => { minBackoffSeconds: undefined, maxBackoffSeconds: undefined, maxDoublings: undefined, + attemptDeadline: undefined, }, }, }); diff --git a/src/v2/providers/scheduler.ts b/src/v2/providers/scheduler.ts index 452e0a6e6..023679d18 100644 --- a/src/v2/providers/scheduler.ts +++ b/src/v2/providers/scheduler.ts @@ -61,22 +61,18 @@ export function getOpts(args: string | ScheduleOptions): SeparatedOpts { opts: {} as options.GlobalOptions, }; } - const retryConfig: any = { - retryCount: args.retryCount, - maxRetrySeconds: args.maxRetrySeconds, - minBackoffSeconds: args.minBackoffSeconds, - maxBackoffSeconds: args.maxBackoffSeconds, - maxDoublings: args.maxDoublings, - }; - if (args.attemptDeadline !== undefined) { - retryConfig.attemptDeadline = args.attemptDeadline; - } - return { schedule: args.schedule, timeZone: args.timeZone, - retryConfig, + retryConfig: { + retryCount: args.retryCount, + maxRetrySeconds: args.maxRetrySeconds, + minBackoffSeconds: args.minBackoffSeconds, + maxBackoffSeconds: args.maxBackoffSeconds, + maxDoublings: args.maxDoublings, + attemptDeadline: args.attemptDeadline, + }, opts: args as options.GlobalOptions, }; } From 579a26ec6a127df1ce4834c2e26744527fabaa3a Mon Sep 17 00:00:00 2001 From: Hung Nguyen Date: Wed, 20 Aug 2025 10:52:04 +0700 Subject: [PATCH 3/3] refactor: change level attemptDeadline same as timeZone level for api --- spec/runtime/manifest.spec.ts | 4 ++-- spec/v1/cloud-functions.spec.ts | 2 +- spec/v1/providers/fixtures.ts | 2 +- spec/v1/providers/pubsub.spec.ts | 4 ---- spec/v2/providers/scheduler.spec.ts | 10 +++++----- src/runtime/manifest.ts | 6 ++---- src/v1/cloud-functions.ts | 1 - src/v2/providers/scheduler.ts | 6 +++--- 8 files changed, 14 insertions(+), 21 deletions(-) diff --git a/spec/runtime/manifest.spec.ts b/spec/runtime/manifest.spec.ts index 7a1b5ee79..5660f369a 100644 --- a/spec/runtime/manifest.spec.ts +++ b/spec/runtime/manifest.spec.ts @@ -259,13 +259,13 @@ describe("initScheduleTrigger", () => { expect(st).to.deep.eq({ schedule: "every 30 minutes", timeZone: RESET_VALUE, + attemptDeadline: RESET_VALUE, retryConfig: { retryCount: RESET_VALUE, maxDoublings: RESET_VALUE, maxRetryDuration: RESET_VALUE, minBackoffDuration: RESET_VALUE, maxBackoffDuration: RESET_VALUE, - attemptDeadline: RESET_VALUE, }, }); }); @@ -287,13 +287,13 @@ describe("initScheduleTrigger", () => { expect(st).to.deep.eq({ schedule: "every 30 minutes", timeZone: RESET_VALUE, + attemptDeadline: RESET_VALUE, retryConfig: { retryCount: RESET_VALUE, maxDoublings: RESET_VALUE, maxRetrySeconds: RESET_VALUE, minBackoffSeconds: RESET_VALUE, maxBackoffSeconds: RESET_VALUE, - attemptDeadline: RESET_VALUE, }, }); }); diff --git a/spec/v1/cloud-functions.spec.ts b/spec/v1/cloud-functions.spec.ts index e17fd813e..c15240035 100644 --- a/spec/v1/cloud-functions.spec.ts +++ b/spec/v1/cloud-functions.spec.ts @@ -206,13 +206,13 @@ describe("makeCloudFunction", () => { platform: "gcfv1", scheduleTrigger: { ...schedule, + attemptDeadline: RESET_VALUE, retryConfig: { ...schedule.retryConfig, maxBackoffDuration: RESET_VALUE, maxDoublings: RESET_VALUE, maxRetryDuration: RESET_VALUE, minBackoffDuration: RESET_VALUE, - attemptDeadline: RESET_VALUE, }, }, labels: {}, diff --git a/spec/v1/providers/fixtures.ts b/spec/v1/providers/fixtures.ts index d15246851..12b3d9f67 100644 --- a/spec/v1/providers/fixtures.ts +++ b/spec/v1/providers/fixtures.ts @@ -46,6 +46,6 @@ export const MINIMAL_SCHEDULE_TRIGGER: ManifestEndpoint["scheduleTrigger"] = { maxBackoffDuration: options.RESET_VALUE, minBackoffDuration: options.RESET_VALUE, maxDoublings: options.RESET_VALUE, - attemptDeadline: options.RESET_VALUE, }, + attemptDeadline: options.RESET_VALUE, }; diff --git a/spec/v1/providers/pubsub.spec.ts b/spec/v1/providers/pubsub.spec.ts index 3d0f41d2c..b56aa98be 100644 --- a/spec/v1/providers/pubsub.spec.ts +++ b/spec/v1/providers/pubsub.spec.ts @@ -217,7 +217,6 @@ describe("Pubsub Functions", () => { schedule: "every 5 minutes", retryConfig: { ...retryConfig, - attemptDeadline: RESET_VALUE, }, }); expect(result.__endpoint.labels).to.be.empty; @@ -254,7 +253,6 @@ describe("Pubsub Functions", () => { schedule: "every 5 minutes", retryConfig: { ...retryConfig, - attemptDeadline: RESET_VALUE, }, timeZone: "America/New_York", }); @@ -349,7 +347,6 @@ describe("Pubsub Functions", () => { timeZone: RESET_VALUE, retryConfig: { ...retryConfig, - attemptDeadline: RESET_VALUE, }, }); expect(result.__endpoint.region).to.deep.equal(["us-east1"]); @@ -393,7 +390,6 @@ describe("Pubsub Functions", () => { timeZone: "America/New_York", retryConfig: { ...retryConfig, - attemptDeadline: RESET_VALUE, }, }); expect(result.__endpoint.region).to.deep.equal(["us-east1"]); diff --git a/spec/v2/providers/scheduler.spec.ts b/spec/v2/providers/scheduler.spec.ts index b3fd04daa..5946e77cd 100644 --- a/spec/v2/providers/scheduler.spec.ts +++ b/spec/v2/providers/scheduler.spec.ts @@ -38,8 +38,8 @@ const MINIMAL_SCHEDULE_TRIGGER: ManifestEndpoint["scheduleTrigger"] = { minBackoffSeconds: options.RESET_VALUE, maxBackoffSeconds: options.RESET_VALUE, maxDoublings: options.RESET_VALUE, - attemptDeadline: options.RESET_VALUE, }, + attemptDeadline: options.RESET_VALUE, }; describe("schedule", () => { @@ -74,8 +74,8 @@ describe("schedule", () => { minBackoffSeconds: 2, maxBackoffSeconds: 3, maxDoublings: 4, - attemptDeadline: "120s", }, + attemptDeadline: "120s", opts: { ...options, memory: "128MiB", @@ -115,7 +115,7 @@ describe("schedule", () => { () => undefined ); - expect(schfn.__endpoint.scheduleTrigger?.retryConfig?.attemptDeadline).to.equal( + expect(schfn.__endpoint.scheduleTrigger?.attemptDeadline).to.equal( "320s" ); }); @@ -151,8 +151,8 @@ describe("schedule", () => { minBackoffSeconds: 11, maxBackoffSeconds: 12, maxDoublings: 2, - attemptDeadline: "120s", }, + attemptDeadline: "120s", }, }); expect(schfn.__requiredAPIs).to.deep.eq([ @@ -178,13 +178,13 @@ describe("schedule", () => { scheduleTrigger: { schedule: "* * * * *", timeZone: undefined, + attemptDeadline: undefined, retryConfig: { retryCount: undefined, maxRetrySeconds: undefined, minBackoffSeconds: undefined, maxBackoffSeconds: undefined, maxDoublings: undefined, - attemptDeadline: undefined, }, }, }); diff --git a/src/runtime/manifest.ts b/src/runtime/manifest.ts index 235517dfc..2744dac90 100644 --- a/src/runtime/manifest.ts +++ b/src/runtime/manifest.ts @@ -107,8 +107,8 @@ export interface ManifestEndpoint { maxRetryDuration?: string | Expression | ResetValue; minBackoffDuration?: string | Expression | ResetValue; maxBackoffDuration?: string | Expression | ResetValue; - attemptDeadline?: string | Expression | ResetValue; }; + attemptDeadline?: string | Expression | ResetValue; }; blockingTrigger?: { @@ -255,7 +255,6 @@ const RESETTABLE_V1_SCHEDULE_OPTIONS: Omit< maxRetryDuration: null, maxBackoffDuration: null, minBackoffDuration: null, - attemptDeadline: null, }; const RESETTABLE_V2_SCHEDULE_OPTIONS: Omit< @@ -267,7 +266,6 @@ const RESETTABLE_V2_SCHEDULE_OPTIONS: Omit< maxRetrySeconds: null, minBackoffSeconds: null, maxBackoffSeconds: null, - attemptDeadline: null, }; function initScheduleTrigger( @@ -283,7 +281,7 @@ function initScheduleTrigger( for (const key of Object.keys(resetOptions)) { scheduleTrigger.retryConfig[key] = RESET_VALUE; } - scheduleTrigger = { ...scheduleTrigger, timeZone: RESET_VALUE }; + scheduleTrigger = { ...scheduleTrigger, timeZone: RESET_VALUE, attemptDeadline: RESET_VALUE }; } return scheduleTrigger; } diff --git a/src/v1/cloud-functions.ts b/src/v1/cloud-functions.ts index bc4434d1d..adcf5668b 100644 --- a/src/v1/cloud-functions.ts +++ b/src/v1/cloud-functions.ts @@ -486,7 +486,6 @@ export function makeCloudFunction({ "maxBackoffDuration", "maxRetryDuration", "minBackoffDuration", - "attemptDeadline" ); } else { endpoint.eventTrigger = { diff --git a/src/v2/providers/scheduler.ts b/src/v2/providers/scheduler.ts index 023679d18..c214f4bb6 100644 --- a/src/v2/providers/scheduler.ts +++ b/src/v2/providers/scheduler.ts @@ -48,8 +48,8 @@ interface SeparatedOpts { minBackoffSeconds?: number | Expression | ResetValue; maxBackoffSeconds?: number | Expression | ResetValue; maxDoublings?: number | Expression | ResetValue; - attemptDeadline?: string | Expression | ResetValue; }; + attemptDeadline?: string | Expression | ResetValue; opts: options.GlobalOptions; } @@ -71,8 +71,8 @@ export function getOpts(args: string | ScheduleOptions): SeparatedOpts { minBackoffSeconds: args.minBackoffSeconds, maxBackoffSeconds: args.maxBackoffSeconds, maxDoublings: args.maxDoublings, - attemptDeadline: args.attemptDeadline, }, + attemptDeadline: args.attemptDeadline, opts: args as options.GlobalOptions, }; } @@ -206,6 +206,7 @@ export function onSchedule( }; copyIfPresent(ep.scheduleTrigger, separatedOpts, "timeZone"); + copyIfPresent(ep.scheduleTrigger, separatedOpts, "attemptDeadline"); copyIfPresent( ep.scheduleTrigger.retryConfig, separatedOpts.retryConfig, @@ -214,7 +215,6 @@ export function onSchedule( "minBackoffSeconds", "maxBackoffSeconds", "maxDoublings", - "attemptDeadline" ); func.__endpoint = ep;