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:
parent
8050cbf39e
commit
ab755a07d8
3 changed files with 197 additions and 6 deletions
|
@ -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, "* * * * *");
|
||||||
|
});
|
||||||
|
|
42
cli/tsc/dts/lib.deno.unstable.d.ts
vendored
42
cli/tsc/dts/lib.deno.unstable.d.ts
vendored
|
@ -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>;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue