ai-workflows 2.1.1 → 2.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +1 -1
- package/CHANGELOG.md +17 -1
- package/README.md +305 -184
- package/dist/barrier.d.ts +159 -0
- package/dist/barrier.d.ts.map +1 -0
- package/dist/barrier.js +377 -0
- package/dist/barrier.js.map +1 -0
- package/dist/cascade-context.d.ts +149 -0
- package/dist/cascade-context.d.ts.map +1 -0
- package/dist/cascade-context.js +324 -0
- package/dist/cascade-context.js.map +1 -0
- package/dist/cascade-executor.d.ts +196 -0
- package/dist/cascade-executor.d.ts.map +1 -0
- package/dist/cascade-executor.js +384 -0
- package/dist/cascade-executor.js.map +1 -0
- package/dist/context.d.ts.map +1 -1
- package/dist/context.js +27 -8
- package/dist/context.js.map +1 -1
- package/dist/cron-parser.d.ts +65 -0
- package/dist/cron-parser.d.ts.map +1 -0
- package/dist/cron-parser.js +294 -0
- package/dist/cron-parser.js.map +1 -0
- package/dist/cron-scheduler.d.ts +117 -0
- package/dist/cron-scheduler.d.ts.map +1 -0
- package/dist/cron-scheduler.js +176 -0
- package/dist/cron-scheduler.js.map +1 -0
- package/dist/database-context.d.ts +184 -0
- package/dist/database-context.d.ts.map +1 -0
- package/dist/database-context.js +428 -0
- package/dist/database-context.js.map +1 -0
- package/dist/dependency-graph.d.ts +157 -0
- package/dist/dependency-graph.d.ts.map +1 -0
- package/dist/dependency-graph.js +382 -0
- package/dist/dependency-graph.js.map +1 -0
- package/dist/digital-objects-adapter.d.ts +159 -0
- package/dist/digital-objects-adapter.d.ts.map +1 -0
- package/dist/digital-objects-adapter.js +229 -0
- package/dist/digital-objects-adapter.js.map +1 -0
- package/dist/durable-execution-cloudflare.d.ts +427 -0
- package/dist/durable-execution-cloudflare.d.ts.map +1 -0
- package/dist/durable-execution-cloudflare.js +510 -0
- package/dist/durable-execution-cloudflare.js.map +1 -0
- package/dist/durable-execution.d.ts +482 -0
- package/dist/durable-execution.d.ts.map +1 -0
- package/dist/durable-execution.js +594 -0
- package/dist/durable-execution.js.map +1 -0
- package/dist/durable-workflow.d.ts +176 -0
- package/dist/durable-workflow.d.ts.map +1 -0
- package/dist/durable-workflow.js +552 -0
- package/dist/durable-workflow.js.map +1 -0
- package/dist/every.d.ts +31 -2
- package/dist/every.d.ts.map +1 -1
- package/dist/every.js +63 -32
- package/dist/every.js.map +1 -1
- package/dist/graph/index.d.ts +8 -0
- package/dist/graph/index.d.ts.map +1 -0
- package/dist/graph/index.js +8 -0
- package/dist/graph/index.js.map +1 -0
- package/dist/graph/topological-sort.d.ts +121 -0
- package/dist/graph/topological-sort.d.ts.map +1 -0
- package/dist/graph/topological-sort.js +292 -0
- package/dist/graph/topological-sort.js.map +1 -0
- package/dist/index.d.ts +10 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +25 -0
- package/dist/index.js.map +1 -1
- package/dist/logger.d.ts +101 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +115 -0
- package/dist/logger.js.map +1 -0
- package/dist/on.d.ts +35 -10
- package/dist/on.d.ts.map +1 -1
- package/dist/on.js +53 -19
- package/dist/on.js.map +1 -1
- package/dist/runtime.d.ts +169 -0
- package/dist/runtime.d.ts.map +1 -0
- package/dist/runtime.js +275 -0
- package/dist/runtime.js.map +1 -0
- package/dist/send.d.ts.map +1 -1
- package/dist/send.js +4 -3
- package/dist/send.js.map +1 -1
- package/dist/telemetry.d.ts +150 -0
- package/dist/telemetry.d.ts.map +1 -0
- package/dist/telemetry.js +388 -0
- package/dist/telemetry.js.map +1 -0
- package/dist/timer-registry.d.ts +77 -0
- package/dist/timer-registry.d.ts.map +1 -0
- package/dist/timer-registry.js +154 -0
- package/dist/timer-registry.js.map +1 -0
- package/dist/types.d.ts +105 -6
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +17 -1
- package/dist/types.js.map +1 -1
- package/dist/worker/durable-step.d.ts +481 -0
- package/dist/worker/durable-step.d.ts.map +1 -0
- package/dist/worker/durable-step.js +606 -0
- package/dist/worker/durable-step.js.map +1 -0
- package/dist/worker/index.d.ts +106 -0
- package/dist/worker/index.d.ts.map +1 -0
- package/dist/worker/index.js +124 -0
- package/dist/worker/index.js.map +1 -0
- package/dist/worker/state-adapter.d.ts +230 -0
- package/dist/worker/state-adapter.d.ts.map +1 -0
- package/dist/worker/state-adapter.js +409 -0
- package/dist/worker/state-adapter.js.map +1 -0
- package/dist/worker/topological-executor.d.ts +282 -0
- package/dist/worker/topological-executor.d.ts.map +1 -0
- package/dist/worker/topological-executor.js +396 -0
- package/dist/worker/topological-executor.js.map +1 -0
- package/dist/worker/workflow-builder.d.ts +286 -0
- package/dist/worker/workflow-builder.d.ts.map +1 -0
- package/dist/worker/workflow-builder.js +565 -0
- package/dist/worker/workflow-builder.js.map +1 -0
- package/dist/worker.d.ts +800 -0
- package/dist/worker.d.ts.map +1 -0
- package/dist/worker.js +2428 -0
- package/dist/worker.js.map +1 -0
- package/dist/workflow-builder.d.ts +287 -0
- package/dist/workflow-builder.d.ts.map +1 -0
- package/dist/workflow-builder.js +762 -0
- package/dist/workflow-builder.js.map +1 -0
- package/dist/workflow.d.ts +14 -30
- package/dist/workflow.d.ts.map +1 -1
- package/dist/workflow.js +136 -292
- package/dist/workflow.js.map +1 -1
- package/examples/01-ecommerce-order-pipeline.ts +358 -0
- package/examples/02-content-moderation-cascade.ts +454 -0
- package/examples/03-scheduled-reporting-dependencies.ts +479 -0
- package/examples/04-database-persistence.ts +518 -0
- package/examples/README.md +173 -0
- package/package.json +21 -4
- package/src/__tests__/digital-objects-adapter.test.ts +274 -0
- package/src/__tests__/durable-workflow.test.ts +297 -0
- package/src/barrier.ts +507 -0
- package/src/cascade-context.ts +495 -0
- package/src/cascade-executor.ts +588 -0
- package/src/context.ts +51 -17
- package/src/cron-parser.ts +347 -0
- package/src/cron-scheduler.ts +239 -0
- package/src/database-context.ts +658 -0
- package/src/dependency-graph.ts +518 -0
- package/src/digital-objects-adapter.ts +351 -0
- package/src/durable-execution-cloudflare.ts +855 -0
- package/src/durable-execution.ts +1042 -0
- package/src/durable-workflow.ts +717 -0
- package/src/every.ts +104 -35
- package/src/graph/index.ts +19 -0
- package/src/graph/topological-sort.ts +412 -0
- package/src/index.ts +147 -0
- package/src/logger.ts +148 -0
- package/src/on.ts +81 -26
- package/src/runtime.ts +436 -0
- package/src/send.ts +4 -5
- package/src/telemetry.ts +577 -0
- package/src/timer-registry.ts +179 -0
- package/src/types.ts +146 -10
- package/src/worker/durable-step.ts +976 -0
- package/src/worker/index.ts +216 -0
- package/src/worker/state-adapter.ts +589 -0
- package/src/worker/topological-executor.ts +625 -0
- package/src/worker/workflow-builder.ts +871 -0
- package/src/worker.ts +2906 -0
- package/src/workflow-builder.ts +1068 -0
- package/src/workflow.ts +199 -355
- package/test/barrier-join.test.ts +442 -0
- package/test/barrier-unhandled-rejections.test.ts +359 -0
- package/test/cascade-context.test.ts +390 -0
- package/test/cascade-executor.test.ts +852 -0
- package/test/cron-parser.test.ts +314 -0
- package/test/cron-scheduler.test.ts +291 -0
- package/test/database-context.test.ts +770 -0
- package/test/db-provider-adapter.test.ts +862 -0
- package/test/dependency-graph.test.ts +512 -0
- package/test/durable-execution-cloudflare.test.ts +606 -0
- package/test/durable-execution-in-process.test.ts +286 -0
- package/test/durable-execution.test.ts +247 -0
- package/test/e2e/workflow-scenarios.e2e.test.ts +1039 -0
- package/test/graph/topological-sort.test.ts +586 -0
- package/test/integration.test.ts +442 -0
- package/test/rpc-surface.test.ts +946 -0
- package/test/runtime.test.ts +262 -0
- package/test/schedule-timer-cleanup.test.ts +353 -0
- package/test/send-race-conditions.test.ts +400 -0
- package/test/type-safety-every.test.ts +303 -0
- package/test/worker/durable-cascade.test.ts +1117 -0
- package/test/worker/durable-step.test.ts +723 -0
- package/test/worker/topological-executor.test.ts +1240 -0
- package/test/worker/workflow-builder.test.ts +1067 -0
- package/test/worker.test.ts +608 -0
- package/test/workflow-builder.test.ts +1670 -0
- package/test/workflow-cron.test.ts +256 -0
- package/test/workflow-state-adapter.test.ts +923 -0
- package/test/workflow.test.ts +25 -22
- package/tsconfig.json +3 -1
- package/vitest.config.ts +38 -1
- package/vitest.workers.config.ts +44 -0
- package/wrangler.jsonc +22 -0
- package/.turbo/turbo-test.log +0 -7
- package/src/context.js +0 -83
- package/src/every.js +0 -267
- package/src/index.js +0 -71
- package/src/on.js +0 -79
- package/src/send.js +0 -111
- package/src/types.js +0 -4
- package/src/workflow.js +0 -455
- package/test/context.test.js +0 -116
- package/test/every.test.js +0 -282
- package/test/on.test.js +0 -80
- package/test/send.test.js +0 -89
- package/test/workflow.test.js +0 -224
- package/vitest.config.js +0 -7
package/dist/context.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"context.js","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"AAAA;;GAEG;AAWH;;GAEG;AACH,MAAM,UAAU,qBAAqB,CAAC,QAAsB;IAC1D,MAAM,aAAa,GAAkB;QACnC,OAAO,EAAE,EAAE;QACX,OAAO,EAAE,EAAE;KACZ,CAAA;IAED,MAAM,UAAU,GAAG,CAAC,KAA8C,EAAE,EAAE;QACpE,aAAa,CAAC,OAAO,CAAC,IAAI,CAAC;YACzB,GAAG,KAAK;YACR,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;SACtB,CAAC,CAAA;IACJ,CAAC,CAAA;IAED,yFAAyF;IACzF,MAAM,WAAW,GAAG,IAAI,KAAK,CAAC,EAAa,EAAE;QAC3C,GAAG;YACD,OAAO,IAAI,KAAK,
|
|
1
|
+
{"version":3,"file":"context.js","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cron Expression Parser
|
|
3
|
+
*
|
|
4
|
+
* Parses standard 5-field cron expressions:
|
|
5
|
+
* minute hour day-of-month month day-of-week
|
|
6
|
+
*
|
|
7
|
+
* Also supports optional 6-field expressions with seconds:
|
|
8
|
+
* second minute hour day-of-month month day-of-week
|
|
9
|
+
*
|
|
10
|
+
* Supported syntax:
|
|
11
|
+
* - Numbers: 0, 5, 15
|
|
12
|
+
* - Ranges: 1-5, 9-17
|
|
13
|
+
* - Lists: 1,3,5, Mon,Wed,Fri
|
|
14
|
+
* - Steps: star/5, 0-30/5
|
|
15
|
+
* - Wildcards: star (asterisk)
|
|
16
|
+
* - Day names: Mon, Tue, Wed, Thu, Fri, Sat, Sun
|
|
17
|
+
* - Month names: Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec
|
|
18
|
+
*/
|
|
19
|
+
/**
|
|
20
|
+
* Parsed cron expression
|
|
21
|
+
*/
|
|
22
|
+
export interface ParsedCron {
|
|
23
|
+
/** Seconds (0-59) - optional, defaults to [0] */
|
|
24
|
+
seconds: number[];
|
|
25
|
+
/** Minutes (0-59) */
|
|
26
|
+
minutes: number[];
|
|
27
|
+
/** Hours (0-23) */
|
|
28
|
+
hours: number[];
|
|
29
|
+
/** Days of month (1-31) */
|
|
30
|
+
daysOfMonth: number[];
|
|
31
|
+
/** Months (1-12) */
|
|
32
|
+
months: number[];
|
|
33
|
+
/** Days of week (0-6, Sunday = 0) */
|
|
34
|
+
daysOfWeek: number[];
|
|
35
|
+
/** Whether day of month is a wildcard */
|
|
36
|
+
dayOfMonthWildcard: boolean;
|
|
37
|
+
/** Whether day of week is a wildcard */
|
|
38
|
+
dayOfWeekWildcard: boolean;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Parse a cron expression
|
|
42
|
+
*
|
|
43
|
+
* @param expression - Cron expression (5 or 6 fields)
|
|
44
|
+
* @returns ParsedCron object
|
|
45
|
+
* @throws Error if expression is invalid
|
|
46
|
+
*/
|
|
47
|
+
export declare function parseCron(expression: string): ParsedCron;
|
|
48
|
+
/**
|
|
49
|
+
* Check if a date matches a parsed cron expression
|
|
50
|
+
*/
|
|
51
|
+
export declare function matchesCron(date: Date, cron: ParsedCron): boolean;
|
|
52
|
+
/**
|
|
53
|
+
* Find the next date that matches a cron expression
|
|
54
|
+
*
|
|
55
|
+
* @param cron - Parsed cron expression
|
|
56
|
+
* @param from - Start date (defaults to now)
|
|
57
|
+
* @param maxIterations - Maximum iterations to prevent infinite loops
|
|
58
|
+
* @returns Next matching Date or null if not found within iterations
|
|
59
|
+
*/
|
|
60
|
+
export declare function getNextCronDate(cron: ParsedCron, from?: Date, maxIterations?: number): Date | null;
|
|
61
|
+
/**
|
|
62
|
+
* Calculate milliseconds until the next cron occurrence
|
|
63
|
+
*/
|
|
64
|
+
export declare function getNextCronMs(cron: ParsedCron, from?: Date): number | null;
|
|
65
|
+
//# sourceMappingURL=cron-parser.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cron-parser.d.ts","sourceRoot":"","sources":["../src/cron-parser.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,iDAAiD;IACjD,OAAO,EAAE,MAAM,EAAE,CAAA;IACjB,qBAAqB;IACrB,OAAO,EAAE,MAAM,EAAE,CAAA;IACjB,mBAAmB;IACnB,KAAK,EAAE,MAAM,EAAE,CAAA;IACf,2BAA2B;IAC3B,WAAW,EAAE,MAAM,EAAE,CAAA;IACrB,oBAAoB;IACpB,MAAM,EAAE,MAAM,EAAE,CAAA;IAChB,qCAAqC;IACrC,UAAU,EAAE,MAAM,EAAE,CAAA;IACpB,yCAAyC;IACzC,kBAAkB,EAAE,OAAO,CAAA;IAC3B,wCAAwC;IACxC,iBAAiB,EAAE,OAAO,CAAA;CAC3B;AAwGD;;;;;;GAMG;AACH,wBAAgB,SAAS,CAAC,UAAU,EAAE,MAAM,GAAG,UAAU,CA4BxD;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,UAAU,GAAG,OAAO,CAkCjE;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAC7B,IAAI,EAAE,UAAU,EAChB,IAAI,GAAE,IAAiB,EACvB,aAAa,GAAE,MAAsB,GACpC,IAAI,GAAG,IAAI,CA8Fb;AAcD;;GAEG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,UAAU,EAAE,IAAI,GAAE,IAAiB,GAAG,MAAM,GAAG,IAAI,CAItF"}
|
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cron Expression Parser
|
|
3
|
+
*
|
|
4
|
+
* Parses standard 5-field cron expressions:
|
|
5
|
+
* minute hour day-of-month month day-of-week
|
|
6
|
+
*
|
|
7
|
+
* Also supports optional 6-field expressions with seconds:
|
|
8
|
+
* second minute hour day-of-month month day-of-week
|
|
9
|
+
*
|
|
10
|
+
* Supported syntax:
|
|
11
|
+
* - Numbers: 0, 5, 15
|
|
12
|
+
* - Ranges: 1-5, 9-17
|
|
13
|
+
* - Lists: 1,3,5, Mon,Wed,Fri
|
|
14
|
+
* - Steps: star/5, 0-30/5
|
|
15
|
+
* - Wildcards: star (asterisk)
|
|
16
|
+
* - Day names: Mon, Tue, Wed, Thu, Fri, Sat, Sun
|
|
17
|
+
* - Month names: Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec
|
|
18
|
+
*/
|
|
19
|
+
/**
|
|
20
|
+
* Day name to number mapping (Sunday = 0)
|
|
21
|
+
*/
|
|
22
|
+
const DAY_NAMES = {
|
|
23
|
+
sun: 0,
|
|
24
|
+
mon: 1,
|
|
25
|
+
tue: 2,
|
|
26
|
+
wed: 3,
|
|
27
|
+
thu: 4,
|
|
28
|
+
fri: 5,
|
|
29
|
+
sat: 6,
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* Month name to number mapping (January = 1)
|
|
33
|
+
*/
|
|
34
|
+
const MONTH_NAMES = {
|
|
35
|
+
jan: 1,
|
|
36
|
+
feb: 2,
|
|
37
|
+
mar: 3,
|
|
38
|
+
apr: 4,
|
|
39
|
+
may: 5,
|
|
40
|
+
jun: 6,
|
|
41
|
+
jul: 7,
|
|
42
|
+
aug: 8,
|
|
43
|
+
sep: 9,
|
|
44
|
+
oct: 10,
|
|
45
|
+
nov: 11,
|
|
46
|
+
dec: 12,
|
|
47
|
+
};
|
|
48
|
+
/**
|
|
49
|
+
* Parse a single cron field value
|
|
50
|
+
*/
|
|
51
|
+
function parseFieldValue(value, min, max, names) {
|
|
52
|
+
// Check for named value (e.g., Mon, Jan)
|
|
53
|
+
if (names) {
|
|
54
|
+
const lower = value.toLowerCase();
|
|
55
|
+
if (lower in names) {
|
|
56
|
+
return names[lower];
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
const num = parseInt(value, 10);
|
|
60
|
+
if (isNaN(num) || num < min || num > max) {
|
|
61
|
+
throw new Error(`Invalid cron field value: ${value} (expected ${min}-${max})`);
|
|
62
|
+
}
|
|
63
|
+
return num;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Parse a single cron field
|
|
67
|
+
* Examples: "0", "*", "1-5", "* /15" (no space), "1,3,5"
|
|
68
|
+
*/
|
|
69
|
+
function parseField(field, min, max, names) {
|
|
70
|
+
const values = new Set();
|
|
71
|
+
// Split by comma for lists
|
|
72
|
+
const parts = field.split(',');
|
|
73
|
+
for (const part of parts) {
|
|
74
|
+
// Check for step (e.g., */5 or 0-30/5)
|
|
75
|
+
const stepMatch = part.match(/^(.+)\/(\d+)$/);
|
|
76
|
+
const step = stepMatch ? parseInt(stepMatch[2], 10) : 1;
|
|
77
|
+
const range = stepMatch ? stepMatch[1] : part;
|
|
78
|
+
let start;
|
|
79
|
+
let end;
|
|
80
|
+
if (range === '*') {
|
|
81
|
+
start = min;
|
|
82
|
+
end = max;
|
|
83
|
+
}
|
|
84
|
+
else if (range.includes('-')) {
|
|
85
|
+
// Range (e.g., 1-5)
|
|
86
|
+
const [rangeStart, rangeEnd] = range.split('-');
|
|
87
|
+
start = parseFieldValue(rangeStart, min, max, names);
|
|
88
|
+
end = parseFieldValue(rangeEnd, min, max, names);
|
|
89
|
+
}
|
|
90
|
+
else {
|
|
91
|
+
// Single value
|
|
92
|
+
start = parseFieldValue(range, min, max, names);
|
|
93
|
+
end = start;
|
|
94
|
+
}
|
|
95
|
+
// Generate values with step
|
|
96
|
+
for (let i = start; i <= end; i += step) {
|
|
97
|
+
values.add(i);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return Array.from(values).sort((a, b) => a - b);
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Parse a cron expression
|
|
104
|
+
*
|
|
105
|
+
* @param expression - Cron expression (5 or 6 fields)
|
|
106
|
+
* @returns ParsedCron object
|
|
107
|
+
* @throws Error if expression is invalid
|
|
108
|
+
*/
|
|
109
|
+
export function parseCron(expression) {
|
|
110
|
+
const fields = expression.trim().split(/\s+/);
|
|
111
|
+
if (fields.length < 5 || fields.length > 6) {
|
|
112
|
+
throw new Error(`Invalid cron expression: expected 5 or 6 fields, got ${fields.length}`);
|
|
113
|
+
}
|
|
114
|
+
// Determine if we have seconds field
|
|
115
|
+
const hasSeconds = fields.length === 6;
|
|
116
|
+
const offset = hasSeconds ? 0 : -1;
|
|
117
|
+
const secondsField = hasSeconds ? fields[0] : '0';
|
|
118
|
+
const minutesField = fields[offset + 1];
|
|
119
|
+
const hoursField = fields[offset + 2];
|
|
120
|
+
const daysOfMonthField = fields[offset + 3];
|
|
121
|
+
const monthsField = fields[offset + 4];
|
|
122
|
+
const daysOfWeekField = fields[offset + 5];
|
|
123
|
+
return {
|
|
124
|
+
seconds: parseField(secondsField, 0, 59),
|
|
125
|
+
minutes: parseField(minutesField, 0, 59),
|
|
126
|
+
hours: parseField(hoursField, 0, 23),
|
|
127
|
+
daysOfMonth: parseField(daysOfMonthField, 1, 31),
|
|
128
|
+
months: parseField(monthsField, 1, 12, MONTH_NAMES),
|
|
129
|
+
daysOfWeek: parseField(daysOfWeekField, 0, 6, DAY_NAMES),
|
|
130
|
+
dayOfMonthWildcard: daysOfMonthField === '*',
|
|
131
|
+
dayOfWeekWildcard: daysOfWeekField === '*',
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Check if a date matches a parsed cron expression
|
|
136
|
+
*/
|
|
137
|
+
export function matchesCron(date, cron) {
|
|
138
|
+
const second = date.getSeconds();
|
|
139
|
+
const minute = date.getMinutes();
|
|
140
|
+
const hour = date.getHours();
|
|
141
|
+
const dayOfMonth = date.getDate();
|
|
142
|
+
const month = date.getMonth() + 1; // JavaScript months are 0-indexed
|
|
143
|
+
const dayOfWeek = date.getDay();
|
|
144
|
+
// Check basic fields
|
|
145
|
+
if (!cron.seconds.includes(second))
|
|
146
|
+
return false;
|
|
147
|
+
if (!cron.minutes.includes(minute))
|
|
148
|
+
return false;
|
|
149
|
+
if (!cron.hours.includes(hour))
|
|
150
|
+
return false;
|
|
151
|
+
if (!cron.months.includes(month))
|
|
152
|
+
return false;
|
|
153
|
+
// Handle day matching (special cron semantics)
|
|
154
|
+
// If both day-of-month and day-of-week are specified (not wildcards),
|
|
155
|
+
// either one matching is sufficient (OR logic)
|
|
156
|
+
// If only one is specified, that one must match
|
|
157
|
+
const domMatches = cron.daysOfMonth.includes(dayOfMonth);
|
|
158
|
+
const dowMatches = cron.daysOfWeek.includes(dayOfWeek);
|
|
159
|
+
if (cron.dayOfMonthWildcard && cron.dayOfWeekWildcard) {
|
|
160
|
+
// Both wildcards - any day matches
|
|
161
|
+
return true;
|
|
162
|
+
}
|
|
163
|
+
else if (cron.dayOfMonthWildcard) {
|
|
164
|
+
// Only day-of-week specified
|
|
165
|
+
return dowMatches;
|
|
166
|
+
}
|
|
167
|
+
else if (cron.dayOfWeekWildcard) {
|
|
168
|
+
// Only day-of-month specified
|
|
169
|
+
return domMatches;
|
|
170
|
+
}
|
|
171
|
+
else {
|
|
172
|
+
// Both specified - OR logic (standard cron behavior)
|
|
173
|
+
return domMatches || dowMatches;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Find the next date that matches a cron expression
|
|
178
|
+
*
|
|
179
|
+
* @param cron - Parsed cron expression
|
|
180
|
+
* @param from - Start date (defaults to now)
|
|
181
|
+
* @param maxIterations - Maximum iterations to prevent infinite loops
|
|
182
|
+
* @returns Next matching Date or null if not found within iterations
|
|
183
|
+
*/
|
|
184
|
+
export function getNextCronDate(cron, from = new Date(), maxIterations = 366 * 24 * 60 // ~1 year of minutes
|
|
185
|
+
) {
|
|
186
|
+
// Start from the next second
|
|
187
|
+
const next = new Date(from.getTime());
|
|
188
|
+
next.setMilliseconds(0);
|
|
189
|
+
next.setSeconds(next.getSeconds() + 1);
|
|
190
|
+
let iterations = 0;
|
|
191
|
+
while (iterations < maxIterations) {
|
|
192
|
+
iterations++;
|
|
193
|
+
// Check if current time matches
|
|
194
|
+
if (matchesCron(next, cron)) {
|
|
195
|
+
return next;
|
|
196
|
+
}
|
|
197
|
+
// Advance to next possible match
|
|
198
|
+
// Start by advancing the smallest unit that doesn't match
|
|
199
|
+
// Check seconds
|
|
200
|
+
if (!cron.seconds.includes(next.getSeconds())) {
|
|
201
|
+
const nextSecond = findNextValue(next.getSeconds(), cron.seconds);
|
|
202
|
+
if (nextSecond !== null) {
|
|
203
|
+
next.setSeconds(nextSecond);
|
|
204
|
+
}
|
|
205
|
+
else {
|
|
206
|
+
// Roll over to next minute
|
|
207
|
+
next.setSeconds(cron.seconds[0]);
|
|
208
|
+
next.setMinutes(next.getMinutes() + 1);
|
|
209
|
+
}
|
|
210
|
+
continue;
|
|
211
|
+
}
|
|
212
|
+
// Check minutes
|
|
213
|
+
if (!cron.minutes.includes(next.getMinutes())) {
|
|
214
|
+
const nextMinute = findNextValue(next.getMinutes(), cron.minutes);
|
|
215
|
+
if (nextMinute !== null) {
|
|
216
|
+
next.setMinutes(nextMinute);
|
|
217
|
+
next.setSeconds(cron.seconds[0]);
|
|
218
|
+
}
|
|
219
|
+
else {
|
|
220
|
+
// Roll over to next hour
|
|
221
|
+
next.setMinutes(cron.minutes[0]);
|
|
222
|
+
next.setSeconds(cron.seconds[0]);
|
|
223
|
+
next.setHours(next.getHours() + 1);
|
|
224
|
+
}
|
|
225
|
+
continue;
|
|
226
|
+
}
|
|
227
|
+
// Check hours
|
|
228
|
+
if (!cron.hours.includes(next.getHours())) {
|
|
229
|
+
const nextHour = findNextValue(next.getHours(), cron.hours);
|
|
230
|
+
if (nextHour !== null) {
|
|
231
|
+
next.setHours(nextHour);
|
|
232
|
+
next.setMinutes(cron.minutes[0]);
|
|
233
|
+
next.setSeconds(cron.seconds[0]);
|
|
234
|
+
}
|
|
235
|
+
else {
|
|
236
|
+
// Roll over to next day
|
|
237
|
+
next.setHours(cron.hours[0]);
|
|
238
|
+
next.setMinutes(cron.minutes[0]);
|
|
239
|
+
next.setSeconds(cron.seconds[0]);
|
|
240
|
+
next.setDate(next.getDate() + 1);
|
|
241
|
+
}
|
|
242
|
+
continue;
|
|
243
|
+
}
|
|
244
|
+
// Check month
|
|
245
|
+
if (!cron.months.includes(next.getMonth() + 1)) {
|
|
246
|
+
const nextMonth = findNextValue(next.getMonth() + 1, cron.months);
|
|
247
|
+
if (nextMonth !== null) {
|
|
248
|
+
next.setMonth(nextMonth - 1);
|
|
249
|
+
next.setDate(1);
|
|
250
|
+
next.setHours(cron.hours[0]);
|
|
251
|
+
next.setMinutes(cron.minutes[0]);
|
|
252
|
+
next.setSeconds(cron.seconds[0]);
|
|
253
|
+
}
|
|
254
|
+
else {
|
|
255
|
+
// Roll over to next year
|
|
256
|
+
next.setFullYear(next.getFullYear() + 1);
|
|
257
|
+
next.setMonth(cron.months[0] - 1);
|
|
258
|
+
next.setDate(1);
|
|
259
|
+
next.setHours(cron.hours[0]);
|
|
260
|
+
next.setMinutes(cron.minutes[0]);
|
|
261
|
+
next.setSeconds(cron.seconds[0]);
|
|
262
|
+
}
|
|
263
|
+
continue;
|
|
264
|
+
}
|
|
265
|
+
// Day checks are complex due to OR semantics
|
|
266
|
+
// Just advance by one day and re-check
|
|
267
|
+
next.setDate(next.getDate() + 1);
|
|
268
|
+
next.setHours(cron.hours[0]);
|
|
269
|
+
next.setMinutes(cron.minutes[0]);
|
|
270
|
+
next.setSeconds(cron.seconds[0]);
|
|
271
|
+
}
|
|
272
|
+
return null;
|
|
273
|
+
}
|
|
274
|
+
/**
|
|
275
|
+
* Find the next value in a sorted array that is greater than the current value
|
|
276
|
+
*/
|
|
277
|
+
function findNextValue(current, values) {
|
|
278
|
+
for (const value of values) {
|
|
279
|
+
if (value > current) {
|
|
280
|
+
return value;
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
return null;
|
|
284
|
+
}
|
|
285
|
+
/**
|
|
286
|
+
* Calculate milliseconds until the next cron occurrence
|
|
287
|
+
*/
|
|
288
|
+
export function getNextCronMs(cron, from = new Date()) {
|
|
289
|
+
const next = getNextCronDate(cron, from);
|
|
290
|
+
if (!next)
|
|
291
|
+
return null;
|
|
292
|
+
return next.getTime() - from.getTime();
|
|
293
|
+
}
|
|
294
|
+
//# sourceMappingURL=cron-parser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cron-parser.js","sourceRoot":"","sources":["../src/cron-parser.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cron Scheduler
|
|
3
|
+
*
|
|
4
|
+
* Provides scheduling functionality for cron expressions using accurate
|
|
5
|
+
* time-based scheduling rather than polling.
|
|
6
|
+
*
|
|
7
|
+
* Uses a self-adjusting timer approach:
|
|
8
|
+
* 1. Calculate time until next cron occurrence
|
|
9
|
+
* 2. Set a timeout for that duration
|
|
10
|
+
* 3. Execute handler and schedule next occurrence
|
|
11
|
+
*
|
|
12
|
+
* This is more accurate and efficient than setInterval polling.
|
|
13
|
+
*/
|
|
14
|
+
import { type ParsedCron } from './cron-parser.js';
|
|
15
|
+
/**
|
|
16
|
+
* Scheduled job handle
|
|
17
|
+
*/
|
|
18
|
+
export interface CronJob {
|
|
19
|
+
/** Unique job ID */
|
|
20
|
+
id: string;
|
|
21
|
+
/** Original cron expression */
|
|
22
|
+
expression: string;
|
|
23
|
+
/** Parsed cron data */
|
|
24
|
+
cron: ParsedCron;
|
|
25
|
+
/** Handler function */
|
|
26
|
+
handler: () => void | Promise<void>;
|
|
27
|
+
/** Current timer reference */
|
|
28
|
+
timer: NodeJS.Timeout | null;
|
|
29
|
+
/** Next scheduled run time */
|
|
30
|
+
nextRun: Date | null;
|
|
31
|
+
/** Whether the job is running */
|
|
32
|
+
running: boolean;
|
|
33
|
+
/** Whether the job is stopped */
|
|
34
|
+
stopped: boolean;
|
|
35
|
+
/** Error handler */
|
|
36
|
+
onError?: (error: Error) => void;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Create a cron job
|
|
40
|
+
*
|
|
41
|
+
* @param expression - Cron expression (5 or 6 fields)
|
|
42
|
+
* @param handler - Function to execute on each occurrence
|
|
43
|
+
* @param options - Optional configuration
|
|
44
|
+
* @returns CronJob handle for managing the job
|
|
45
|
+
*
|
|
46
|
+
* @example
|
|
47
|
+
* ```ts
|
|
48
|
+
* // Run every hour at minute 0
|
|
49
|
+
* const job = createCronJob('0 * * * *', () => {
|
|
50
|
+
* console.log('Hourly task')
|
|
51
|
+
* })
|
|
52
|
+
*
|
|
53
|
+
* // Run Monday at 9am
|
|
54
|
+
* const monday9am = createCronJob('0 9 * * 1', async () => {
|
|
55
|
+
* await sendReport()
|
|
56
|
+
* })
|
|
57
|
+
*
|
|
58
|
+
* // Stop the job
|
|
59
|
+
* job.stop()
|
|
60
|
+
* ```
|
|
61
|
+
*/
|
|
62
|
+
export declare function createCronJob(expression: string, handler: () => void | Promise<void>, options?: {
|
|
63
|
+
id?: string;
|
|
64
|
+
onError?: (error: Error) => void;
|
|
65
|
+
startImmediately?: boolean;
|
|
66
|
+
}): CronJob;
|
|
67
|
+
/**
|
|
68
|
+
* Stop a cron job
|
|
69
|
+
*/
|
|
70
|
+
export declare function stopCronJob(job: CronJob): void;
|
|
71
|
+
/**
|
|
72
|
+
* Start a stopped cron job
|
|
73
|
+
*/
|
|
74
|
+
export declare function startCronJob(job: CronJob): void;
|
|
75
|
+
/**
|
|
76
|
+
* Get all active cron jobs
|
|
77
|
+
*/
|
|
78
|
+
export declare function getActiveCronJobs(): CronJob[];
|
|
79
|
+
/**
|
|
80
|
+
* Stop all active cron jobs
|
|
81
|
+
*/
|
|
82
|
+
export declare function stopAllCronJobs(): void;
|
|
83
|
+
/**
|
|
84
|
+
* Get the count of active cron jobs
|
|
85
|
+
*/
|
|
86
|
+
export declare function getActiveCronJobCount(): number;
|
|
87
|
+
/**
|
|
88
|
+
* Cron job registry object for external access
|
|
89
|
+
*/
|
|
90
|
+
export declare const cronJobRegistry: {
|
|
91
|
+
create: typeof createCronJob;
|
|
92
|
+
stop: typeof stopCronJob;
|
|
93
|
+
start: typeof startCronJob;
|
|
94
|
+
getActive: typeof getActiveCronJobs;
|
|
95
|
+
getActiveCount: typeof getActiveCronJobCount;
|
|
96
|
+
stopAll: typeof stopAllCronJobs;
|
|
97
|
+
};
|
|
98
|
+
/**
|
|
99
|
+
* Schedule type for cron-based intervals
|
|
100
|
+
* Used to convert schedule intervals to cron jobs
|
|
101
|
+
*/
|
|
102
|
+
export interface CronScheduleOptions {
|
|
103
|
+
/** Unique identifier for the schedule */
|
|
104
|
+
id?: string;
|
|
105
|
+
/** Error handler */
|
|
106
|
+
onError?: (error: Error) => void;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Create a schedule from a cron expression or well-known pattern
|
|
110
|
+
*
|
|
111
|
+
* @param expression - Cron expression or known pattern name
|
|
112
|
+
* @param handler - Function to execute
|
|
113
|
+
* @param options - Optional configuration
|
|
114
|
+
* @returns CronJob handle
|
|
115
|
+
*/
|
|
116
|
+
export declare function schedule(expression: string, handler: () => void | Promise<void>, options?: CronScheduleOptions): CronJob;
|
|
117
|
+
//# sourceMappingURL=cron-scheduler.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cron-scheduler.d.ts","sourceRoot":"","sources":["../src/cron-scheduler.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAA8B,KAAK,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAG9E;;GAEG;AACH,MAAM,WAAW,OAAO;IACtB,oBAAoB;IACpB,EAAE,EAAE,MAAM,CAAA;IACV,+BAA+B;IAC/B,UAAU,EAAE,MAAM,CAAA;IAClB,uBAAuB;IACvB,IAAI,EAAE,UAAU,CAAA;IAChB,uBAAuB;IACvB,OAAO,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IACnC,8BAA8B;IAC9B,KAAK,EAAE,MAAM,CAAC,OAAO,GAAG,IAAI,CAAA;IAC5B,8BAA8B;IAC9B,OAAO,EAAE,IAAI,GAAG,IAAI,CAAA;IACpB,iCAAiC;IACjC,OAAO,EAAE,OAAO,CAAA;IAChB,iCAAiC;IACjC,OAAO,EAAE,OAAO,CAAA;IAChB,oBAAoB;IACpB,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAA;CACjC;AAYD;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,aAAa,CAC3B,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,EACnC,OAAO,GAAE;IACP,EAAE,CAAC,EAAE,MAAM,CAAA;IACX,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAA;IAChC,gBAAgB,CAAC,EAAE,OAAO,CAAA;CACtB,GACL,OAAO,CAwBT;AA6CD;;GAEG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,OAAO,GAAG,IAAI,CAQ9C;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,OAAO,GAAG,IAAI,CAI/C;AAED;;GAEG;AACH,wBAAgB,iBAAiB,IAAI,OAAO,EAAE,CAE7C;AAED;;GAEG;AACH,wBAAgB,eAAe,IAAI,IAAI,CAItC;AAED;;GAEG;AACH,wBAAgB,qBAAqB,IAAI,MAAM,CAE9C;AAED;;GAEG;AACH,eAAO,MAAM,eAAe;;;;;;;CAO3B,CAAA;AAED;;;GAGG;AACH,MAAM,WAAW,mBAAmB;IAClC,yCAAyC;IACzC,EAAE,CAAC,EAAE,MAAM,CAAA;IACX,oBAAoB;IACpB,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAA;CACjC;AAED;;;;;;;GAOG;AACH,wBAAgB,QAAQ,CACtB,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,EACnC,OAAO,GAAE,mBAAwB,GAChC,OAAO,CAMT"}
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cron Scheduler
|
|
3
|
+
*
|
|
4
|
+
* Provides scheduling functionality for cron expressions using accurate
|
|
5
|
+
* time-based scheduling rather than polling.
|
|
6
|
+
*
|
|
7
|
+
* Uses a self-adjusting timer approach:
|
|
8
|
+
* 1. Calculate time until next cron occurrence
|
|
9
|
+
* 2. Set a timeout for that duration
|
|
10
|
+
* 3. Execute handler and schedule next occurrence
|
|
11
|
+
*
|
|
12
|
+
* This is more accurate and efficient than setInterval polling.
|
|
13
|
+
*/
|
|
14
|
+
import { parseCron, getNextCronDate } from './cron-parser.js';
|
|
15
|
+
import { getLogger } from './logger.js';
|
|
16
|
+
/**
|
|
17
|
+
* Job counter for unique IDs
|
|
18
|
+
*/
|
|
19
|
+
let jobCounter = 0;
|
|
20
|
+
/**
|
|
21
|
+
* Active cron jobs
|
|
22
|
+
*/
|
|
23
|
+
const activeJobs = new Map();
|
|
24
|
+
/**
|
|
25
|
+
* Create a cron job
|
|
26
|
+
*
|
|
27
|
+
* @param expression - Cron expression (5 or 6 fields)
|
|
28
|
+
* @param handler - Function to execute on each occurrence
|
|
29
|
+
* @param options - Optional configuration
|
|
30
|
+
* @returns CronJob handle for managing the job
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* ```ts
|
|
34
|
+
* // Run every hour at minute 0
|
|
35
|
+
* const job = createCronJob('0 * * * *', () => {
|
|
36
|
+
* console.log('Hourly task')
|
|
37
|
+
* })
|
|
38
|
+
*
|
|
39
|
+
* // Run Monday at 9am
|
|
40
|
+
* const monday9am = createCronJob('0 9 * * 1', async () => {
|
|
41
|
+
* await sendReport()
|
|
42
|
+
* })
|
|
43
|
+
*
|
|
44
|
+
* // Stop the job
|
|
45
|
+
* job.stop()
|
|
46
|
+
* ```
|
|
47
|
+
*/
|
|
48
|
+
export function createCronJob(expression, handler, options = {}) {
|
|
49
|
+
const cron = parseCron(expression);
|
|
50
|
+
const id = options.id ?? `cron-job-${++jobCounter}`;
|
|
51
|
+
const job = {
|
|
52
|
+
id,
|
|
53
|
+
expression,
|
|
54
|
+
cron,
|
|
55
|
+
handler,
|
|
56
|
+
timer: null,
|
|
57
|
+
nextRun: null,
|
|
58
|
+
running: false,
|
|
59
|
+
stopped: false,
|
|
60
|
+
...(options.onError !== undefined && { onError: options.onError }),
|
|
61
|
+
};
|
|
62
|
+
activeJobs.set(id, job);
|
|
63
|
+
// Start immediately by default
|
|
64
|
+
if (options.startImmediately !== false) {
|
|
65
|
+
scheduleNext(job);
|
|
66
|
+
}
|
|
67
|
+
return job;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Schedule the next execution of a cron job
|
|
71
|
+
*/
|
|
72
|
+
function scheduleNext(job) {
|
|
73
|
+
if (job.stopped)
|
|
74
|
+
return;
|
|
75
|
+
const now = new Date();
|
|
76
|
+
const nextRun = getNextCronDate(job.cron, now);
|
|
77
|
+
if (!nextRun) {
|
|
78
|
+
getLogger().warn(`[cron] Could not calculate next run for job ${job.id}`);
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
job.nextRun = nextRun;
|
|
82
|
+
const delay = nextRun.getTime() - now.getTime();
|
|
83
|
+
// Clear any existing timer
|
|
84
|
+
if (job.timer) {
|
|
85
|
+
clearTimeout(job.timer);
|
|
86
|
+
}
|
|
87
|
+
// Schedule next execution
|
|
88
|
+
job.timer = setTimeout(async () => {
|
|
89
|
+
if (job.stopped)
|
|
90
|
+
return;
|
|
91
|
+
job.running = true;
|
|
92
|
+
try {
|
|
93
|
+
await job.handler();
|
|
94
|
+
}
|
|
95
|
+
catch (error) {
|
|
96
|
+
if (job.onError) {
|
|
97
|
+
job.onError(error instanceof Error ? error : new Error(String(error)));
|
|
98
|
+
}
|
|
99
|
+
else {
|
|
100
|
+
getLogger().error(`[cron] Error in job ${job.id}:`, error);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
finally {
|
|
104
|
+
job.running = false;
|
|
105
|
+
// Schedule next occurrence
|
|
106
|
+
scheduleNext(job);
|
|
107
|
+
}
|
|
108
|
+
}, delay);
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Stop a cron job
|
|
112
|
+
*/
|
|
113
|
+
export function stopCronJob(job) {
|
|
114
|
+
job.stopped = true;
|
|
115
|
+
if (job.timer) {
|
|
116
|
+
clearTimeout(job.timer);
|
|
117
|
+
job.timer = null;
|
|
118
|
+
}
|
|
119
|
+
job.nextRun = null;
|
|
120
|
+
activeJobs.delete(job.id);
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Start a stopped cron job
|
|
124
|
+
*/
|
|
125
|
+
export function startCronJob(job) {
|
|
126
|
+
job.stopped = false;
|
|
127
|
+
scheduleNext(job);
|
|
128
|
+
activeJobs.set(job.id, job);
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Get all active cron jobs
|
|
132
|
+
*/
|
|
133
|
+
export function getActiveCronJobs() {
|
|
134
|
+
return Array.from(activeJobs.values());
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Stop all active cron jobs
|
|
138
|
+
*/
|
|
139
|
+
export function stopAllCronJobs() {
|
|
140
|
+
for (const job of activeJobs.values()) {
|
|
141
|
+
stopCronJob(job);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Get the count of active cron jobs
|
|
146
|
+
*/
|
|
147
|
+
export function getActiveCronJobCount() {
|
|
148
|
+
return activeJobs.size;
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Cron job registry object for external access
|
|
152
|
+
*/
|
|
153
|
+
export const cronJobRegistry = {
|
|
154
|
+
create: createCronJob,
|
|
155
|
+
stop: stopCronJob,
|
|
156
|
+
start: startCronJob,
|
|
157
|
+
getActive: getActiveCronJobs,
|
|
158
|
+
getActiveCount: getActiveCronJobCount,
|
|
159
|
+
stopAll: stopAllCronJobs,
|
|
160
|
+
};
|
|
161
|
+
/**
|
|
162
|
+
* Create a schedule from a cron expression or well-known pattern
|
|
163
|
+
*
|
|
164
|
+
* @param expression - Cron expression or known pattern name
|
|
165
|
+
* @param handler - Function to execute
|
|
166
|
+
* @param options - Optional configuration
|
|
167
|
+
* @returns CronJob handle
|
|
168
|
+
*/
|
|
169
|
+
export function schedule(expression, handler, options = {}) {
|
|
170
|
+
return createCronJob(expression, handler, {
|
|
171
|
+
...(options.id !== undefined && { id: options.id }),
|
|
172
|
+
...(options.onError !== undefined && { onError: options.onError }),
|
|
173
|
+
startImmediately: true,
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
//# sourceMappingURL=cron-scheduler.js.map
|