diff options
author | Igor Zinkovsky <igor@deno.com> | 2023-11-01 11:57:55 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-11-01 11:57:55 -0700 |
commit | 01d3e0f317ca180bbf0ac8a17c6651869110e02f (patch) | |
tree | b8e3bb91e87cf396bfa782f6377158f8a170b32b /ext/cron/01_cron.ts | |
parent | 82643857cc77a80f9a819584035ec147a6114553 (diff) |
feat(cron) implement Deno.cron() (#21019)
This PR adds unstable `Deno.cron` API to trigger execution of cron jobs.
* State: All cron state is in memory. Cron jobs are scheduled according
to the cron schedule expression and the current time. No state is
persisted to disk.
* Time zone: Cron expressions specify time in UTC.
* Overlapping executions: not permitted. If the next scheduled execution
time occurs while the same cron job is still executing, the scheduled
execution is skipped.
* Retries: failed jobs are automatically retried until they succeed or
until retry threshold is reached. Retry policy can be optionally
specified using `options.backoffSchedule`.
Diffstat (limited to 'ext/cron/01_cron.ts')
-rw-r--r-- | ext/cron/01_cron.ts | 58 |
1 files changed, 58 insertions, 0 deletions
diff --git a/ext/cron/01_cron.ts b/ext/cron/01_cron.ts new file mode 100644 index 000000000..a615ae34b --- /dev/null +++ b/ext/cron/01_cron.ts @@ -0,0 +1,58 @@ +// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license. + +// @ts-ignore internal api +const core = Deno.core; + +function cron( + name: string, + schedule: string, + handler: () => Promise<void> | void, + options?: { backoffSchedule?: number[]; signal?: AbortSignal }, +) { + if (name === undefined) { + throw new TypeError("Deno.cron requires a unique name"); + } + if (schedule === undefined) { + throw new TypeError("Deno.cron requires a valid schedule"); + } + if (handler === undefined) { + throw new TypeError("Deno.cron requires a handler"); + } + + const rid = core.ops.op_cron_create( + name, + schedule, + options?.backoffSchedule, + ); + + if (options?.signal) { + const signal = options?.signal; + signal.addEventListener( + "abort", + () => { + core.close(rid); + }, + { once: true }, + ); + } + + return (async () => { + let success = true; + while (true) { + const r = await core.opAsync("op_cron_next", rid, success); + if (r === false) { + break; + } + try { + const result = handler(); + const _res = result instanceof Promise ? (await result) : result; + success = true; + } catch (error) { + console.error(`Exception in cron handler ${name}`, error); + success = false; + } + } + })(); +} + +export { cron }; |