summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRaashid Anwar <raashid12anwar@gmail.com>2023-12-01 03:21:56 +0530
committerGitHub <noreply@github.com>2023-11-30 13:51:56 -0800
commitab755a07d8997a1d41b84e91ca772815c9ef9699 (patch)
tree62361900a2f6de3d1a459c28be785d5c3f8990e2
parent8050cbf39e69c1056eaa95e9e7b0887e50776b40 (diff)
feat(cron): added the support for json type schedule to cron api (#21340)
Added the support for JSON type schedule to cron API; previously it was string only. fixes #21122
-rw-r--r--cli/tests/unit/cron_test.ts93
-rw-r--r--cli/tsc/dts/lib.deno.unstable.d.ts42
-rw-r--r--ext/cron/01_cron.ts68
3 files changed, 197 insertions, 6 deletions
diff --git a/cli/tests/unit/cron_test.ts b/cli/tests/unit/cron_test.ts
index 79918ed2f..2a146bcfa 100644
--- a/cli/tests/unit/cron_test.ts
+++ b/cli/tests/unit/cron_test.ts
@@ -1,5 +1,9 @@
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
import { assertEquals, assertThrows } from "./test_util.ts";
+import {
+ formatToCronSchedule,
+ parseScheduleToString,
+} from "../../../ext/cron/01_cron.ts";
const sleep = (time: number) => new Promise((r) => setTimeout(r, time));
@@ -170,6 +174,31 @@ Deno.test(async function basicTest() {
}
});
+Deno.test(async function basicTestWithJsonFormatScheduleExpression() {
+ Deno.env.set("DENO_CRON_TEST_SCHEDULE_OFFSET", "100");
+
+ let count = 0;
+ const { promise, resolve } = Promise.withResolvers<void>();
+ const ac = new AbortController();
+ const c = Deno.cron(
+ "abc",
+ { minute: { every: 20 } },
+ { signal: ac.signal },
+ () => {
+ count++;
+ if (count > 5) {
+ resolve();
+ }
+ },
+ );
+ try {
+ await promise;
+ } finally {
+ ac.abort();
+ await c;
+ }
+});
+
Deno.test(async function multipleCrons() {
Deno.env.set("DENO_CRON_TEST_SCHEDULE_OFFSET", "100");
@@ -284,3 +313,67 @@ Deno.test(async function retriesWithBackoffScheduleOldApi() {
// The cron should have executed 3 times (1st attempt and 2 retries).
assertEquals(count, 3);
});
+
+Deno.test("formatToCronSchedule - undefined value", () => {
+ const result = formatToCronSchedule();
+ assertEquals(result, "*");
+});
+
+Deno.test("formatToCronSchedule - number value", () => {
+ const result = formatToCronSchedule(5);
+ assertEquals(result, "5");
+});
+
+Deno.test("formatToCronSchedule - exact array value", () => {
+ const result = formatToCronSchedule({ exact: [1, 2, 3] });
+ assertEquals(result, "1,2,3");
+});
+
+Deno.test("formatToCronSchedule - exact number value", () => {
+ const result = formatToCronSchedule({ exact: 5 });
+ assertEquals(result, "5");
+});
+
+Deno.test("formatToCronSchedule - start, end, every values", () => {
+ const result = formatToCronSchedule({ start: 1, end: 10, every: 2 });
+ assertEquals(result, "1-10/2");
+});
+
+Deno.test("formatToCronSchedule - start, end values", () => {
+ const result = formatToCronSchedule({ start: 1, end: 10 });
+ assertEquals(result, "1-10");
+});
+
+Deno.test("formatToCronSchedule - start, every values", () => {
+ const result = formatToCronSchedule({ start: 1, every: 2 });
+ assertEquals(result, "1/2");
+});
+
+Deno.test("formatToCronSchedule - start value", () => {
+ const result = formatToCronSchedule({ start: 1 });
+ assertEquals(result, "1/1");
+});
+
+Deno.test("formatToCronSchedule - end, every values", () => {
+ assertThrows(
+ () => formatToCronSchedule({ end: 10, every: 2 }),
+ TypeError,
+ "Invalid cron schedule",
+ );
+});
+
+Deno.test("Parse CronSchedule to string", () => {
+ const result = parseScheduleToString({
+ minute: { exact: [1, 2, 3] },
+ hour: { start: 1, end: 10, every: 2 },
+ dayOfMonth: { exact: 5 },
+ month: { start: 1, end: 10 },
+ dayOfWeek: { start: 1, every: 2 },
+ });
+ assertEquals(result, "1,2,3 1-10/2 5 1-10 1/2");
+});
+
+Deno.test("Parse schedule to string - string", () => {
+ const result = parseScheduleToString("* * * * *");
+ assertEquals(result, "* * * * *");
+});
diff --git a/cli/tsc/dts/lib.deno.unstable.d.ts b/cli/tsc/dts/lib.deno.unstable.d.ts
index 5cba27a5e..895b7c0c5 100644
--- a/cli/tsc/dts/lib.deno.unstable.d.ts
+++ b/cli/tsc/dts/lib.deno.unstable.d.ts
@@ -1319,9 +1319,39 @@ declare namespace Deno {
/** **UNSTABLE**: New API, yet to be vetted.
*
+ * CronScheduleExpression is used as the type of `minute`, `hour`,
+ * `dayOfMonth`, `month`, and `dayOfWeek` in {@linkcode CronSchedule}.
+ * @category Cron
+ */
+ type CronScheduleExpression = number | { exact: number | number[] } | {
+ start?: number;
+ end?: number;
+ every?: number;
+ };
+
+ /** **UNSTABLE**: New API, yet to be vetted.
+ *
+ * CronSchedule is the interface used for JSON format
+ * cron `schedule`.
+ * @category Cron
+ */
+ export interface CronSchedule {
+ minute?: CronScheduleExpression;
+ hour?: CronScheduleExpression;
+ dayOfMonth?: CronScheduleExpression;
+ month?: CronScheduleExpression;
+ dayOfWeek?: CronScheduleExpression;
+ }
+
+ /** **UNSTABLE**: New API, yet to be vetted.
+ *
* Create a cron job that will periodically execute the provided handler
* callback based on the specified schedule.
*
+ * `schedule` can be a string in the Unix cron format or in JSON format
+ * as specified by interface {@linkcode CronSchedule}, where time is specified
+ * using UTC time zone.
+ *
* ```ts
* Deno.cron("sample cron", "20 * * * *", () => {
* console.log("cron job executed");
@@ -1339,7 +1369,7 @@ declare namespace Deno {
*/
export function cron(
name: string,
- schedule: string,
+ schedule: string | CronSchedule,
handler: () => Promise<void> | void,
options: { backoffSchedule?: number[]; signal?: AbortSignal },
): Promise<void>;
@@ -1355,14 +1385,15 @@ declare namespace Deno {
* });
* ```
*
- * `schedule` is a Unix cron format expression, where time is specified
+ * `schedule` can be a string in the Unix cron format or in JSON format
+ * as specified by interface {@linkcode CronSchedule}, where time is specified
* using UTC time zone.
*
* @category Cron
*/
export function cron(
name: string,
- schedule: string,
+ schedule: string | CronSchedule,
handler: () => Promise<void> | void,
): Promise<void>;
@@ -1379,7 +1410,8 @@ declare namespace Deno {
* });
* ```
*
- * `schedule` is a Unix cron format expression, where time is specified
+ * `schedule` can be a string in the Unix cron format or in JSON format
+ * as specified by interface {@linkcode CronSchedule}, where time is specified
* using UTC time zone.
*
* `backoffSchedule` option can be used to specify the retry policy for failed
@@ -1392,7 +1424,7 @@ declare namespace Deno {
*/
export function cron(
name: string,
- schedule: string,
+ schedule: string | CronSchedule,
options: { backoffSchedule?: number[]; signal?: AbortSignal },
handler: () => Promise<void> | void,
): Promise<void>;
diff --git a/ext/cron/01_cron.ts b/ext/cron/01_cron.ts
index 30343905c..4a5250618 100644
--- a/ext/cron/01_cron.ts
+++ b/ext/cron/01_cron.ts
@@ -3,9 +3,73 @@
// @ts-ignore internal api
const core = Deno.core;
+export function formatToCronSchedule(
+ value?: number | { exact: number | number[] } | {
+ start?: number;
+ end?: number;
+ every?: number;
+ },
+): string {
+ if (value === undefined) {
+ return "*";
+ } else if (typeof value === "number") {
+ return value.toString();
+ } else {
+ const { exact } = value as { exact: number | number[] };
+ if (exact === undefined) {
+ const { start, end, every } = value as {
+ start?: number;
+ end?: number;
+ every?: number;
+ };
+ if (start !== undefined && end !== undefined && every !== undefined) {
+ return start + "-" + end + "/" + every;
+ } else if (start !== undefined && end !== undefined) {
+ return start + "-" + end;
+ } else if (start !== undefined && every !== undefined) {
+ return start + "/" + every;
+ } else if (start !== undefined) {
+ return start + "/1";
+ } else if (end === undefined && every !== undefined) {
+ return "*/" + every;
+ } else {
+ throw new TypeError("Invalid cron schedule");
+ }
+ } else {
+ if (typeof exact === "number") {
+ return exact.toString();
+ } else {
+ return exact.join(",");
+ }
+ }
+ }
+}
+
+export function parseScheduleToString(
+ schedule: string | Deno.CronSchedule,
+): string {
+ if (typeof schedule === "string") {
+ return schedule;
+ } else {
+ const {
+ minute,
+ hour,
+ dayOfMonth,
+ month,
+ dayOfWeek,
+ } = schedule;
+
+ return formatToCronSchedule(minute) +
+ " " + formatToCronSchedule(hour) +
+ " " + formatToCronSchedule(dayOfMonth) +
+ " " + formatToCronSchedule(month) +
+ " " + formatToCronSchedule(dayOfWeek);
+ }
+}
+
function cron(
name: string,
- schedule: string,
+ schedule: string | Deno.CronSchedule,
handlerOrOptions1:
| (() => Promise<void> | void)
| ({ backoffSchedule?: number[]; signal?: AbortSignal }),
@@ -20,6 +84,8 @@ function cron(
throw new TypeError("Deno.cron requires a valid schedule");
}
+ schedule = parseScheduleToString(schedule);
+
let handler: () => Promise<void> | void;
let options: { backoffSchedule?: number[]; signal?: AbortSignal } | undefined;