1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2025-01-11 08:33:43 -05:00

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
This commit is contained in:
Raashid Anwar 2023-12-01 03:21:56 +05:30 committed by GitHub
parent 8050cbf39e
commit ab755a07d8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 197 additions and 6 deletions

View file

@ -1,5 +1,9 @@
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license. // Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
import { assertEquals, assertThrows } from "./test_util.ts"; 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)); 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.test(async function multipleCrons() {
Deno.env.set("DENO_CRON_TEST_SCHEDULE_OFFSET", "100"); 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). // The cron should have executed 3 times (1st attempt and 2 retries).
assertEquals(count, 3); 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, "* * * * *");
});

View file

@ -1317,11 +1317,41 @@ declare namespace Deno {
*/ */
export function openKv(path?: string): Promise<Deno.Kv>; export function openKv(path?: string): Promise<Deno.Kv>;
/** **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. /** **UNSTABLE**: New API, yet to be vetted.
* *
* Create a cron job that will periodically execute the provided handler * Create a cron job that will periodically execute the provided handler
* callback based on the specified schedule. * 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 * ```ts
* Deno.cron("sample cron", "20 * * * *", () => { * Deno.cron("sample cron", "20 * * * *", () => {
* console.log("cron job executed"); * console.log("cron job executed");
@ -1339,7 +1369,7 @@ declare namespace Deno {
*/ */
export function cron( export function cron(
name: string, name: string,
schedule: string, schedule: string | CronSchedule,
handler: () => Promise<void> | void, handler: () => Promise<void> | void,
options: { backoffSchedule?: number[]; signal?: AbortSignal }, options: { backoffSchedule?: number[]; signal?: AbortSignal },
): Promise<void>; ): 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. * using UTC time zone.
* *
* @category Cron * @category Cron
*/ */
export function cron( export function cron(
name: string, name: string,
schedule: string, schedule: string | CronSchedule,
handler: () => Promise<void> | void, handler: () => Promise<void> | void,
): Promise<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. * using UTC time zone.
* *
* `backoffSchedule` option can be used to specify the retry policy for failed * `backoffSchedule` option can be used to specify the retry policy for failed
@ -1392,7 +1424,7 @@ declare namespace Deno {
*/ */
export function cron( export function cron(
name: string, name: string,
schedule: string, schedule: string | CronSchedule,
options: { backoffSchedule?: number[]; signal?: AbortSignal }, options: { backoffSchedule?: number[]; signal?: AbortSignal },
handler: () => Promise<void> | void, handler: () => Promise<void> | void,
): Promise<void>; ): Promise<void>;

View file

@ -3,9 +3,73 @@
// @ts-ignore internal api // @ts-ignore internal api
const core = Deno.core; 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( function cron(
name: string, name: string,
schedule: string, schedule: string | Deno.CronSchedule,
handlerOrOptions1: handlerOrOptions1:
| (() => Promise<void> | void) | (() => Promise<void> | void)
| ({ backoffSchedule?: number[]; signal?: AbortSignal }), | ({ backoffSchedule?: number[]; signal?: AbortSignal }),
@ -20,6 +84,8 @@ function cron(
throw new TypeError("Deno.cron requires a valid schedule"); throw new TypeError("Deno.cron requires a valid schedule");
} }
schedule = parseScheduleToString(schedule);
let handler: () => Promise<void> | void; let handler: () => Promise<void> | void;
let options: { backoffSchedule?: number[]; signal?: AbortSignal } | undefined; let options: { backoffSchedule?: number[]; signal?: AbortSignal } | undefined;