summaryrefslogtreecommitdiff
path: root/ext/cron/01_cron.ts
diff options
context:
space:
mode:
authorIgor Zinkovsky <igor@deno.com>2023-11-01 11:57:55 -0700
committerGitHub <noreply@github.com>2023-11-01 11:57:55 -0700
commit01d3e0f317ca180bbf0ac8a17c6651869110e02f (patch)
treeb8e3bb91e87cf396bfa782f6377158f8a170b32b /ext/cron/01_cron.ts
parent82643857cc77a80f9a819584035ec147a6114553 (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.ts58
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 };