@zudojs/scheduler 0.0.1 → 1.0.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/README.md +170 -16
- package/dist/index.d.ts +7 -3
- package/dist/index.js +4 -3
- package/dist/scheduler/constants/index.d.ts +1 -1
- package/dist/scheduler/constants/index.js +1 -1
- package/dist/scheduler/constants/schedulerConstants.core.d.ts +0 -4
- package/dist/scheduler/constants/schedulerConstants.core.js +0 -4
- package/dist/scheduler/duration/duration.parser.d.ts +13 -5
- package/dist/scheduler/duration/duration.parser.js +54 -19
- package/dist/scheduler/errors/index.d.ts +1 -1
- package/dist/scheduler/errors/index.js +1 -1
- package/dist/scheduler/errors/scheduler.errors.d.ts +7 -1
- package/dist/scheduler/errors/scheduler.errors.js +7 -1
- package/dist/scheduler/executor/index.d.ts +1 -1
- package/dist/scheduler/executor/index.js +1 -1
- package/dist/scheduler/executor/jobExecutor.core.d.ts +24 -4
- package/dist/scheduler/executor/jobExecutor.core.js +151 -28
- package/dist/scheduler/job/jobOptions.type.d.ts +11 -0
- package/dist/scheduler/priorityQueue/schedulerPriorityQueue.core.d.ts +12 -0
- package/dist/scheduler/priorityQueue/schedulerPriorityQueue.core.js +32 -5
- package/dist/scheduler/registry/jobRegistry.core.d.ts +8 -0
- package/dist/scheduler/registry/jobRegistry.core.js +14 -0
- package/dist/scheduler/schedule/schedule.type.d.ts +11 -6
- package/dist/scheduler/schedule/schedule.type.js +10 -1
- package/dist/scheduler/schedule/scheduleOptions.type.d.ts +24 -1
- package/dist/scheduler/scheduleHandle/index.d.ts +1 -0
- package/dist/scheduler/scheduleHandle/scheduleHandle.type.d.ts +26 -3
- package/dist/scheduler/scheduleHandle/scheduleHandle.type.js +23 -7
- package/dist/scheduler/scheduler.core.d.ts +120 -11
- package/dist/scheduler/scheduler.core.js +424 -53
- package/dist/scheduler/trigger/cron.parser.d.ts +44 -0
- package/dist/scheduler/trigger/cron.parser.js +256 -0
- package/dist/scheduler/trigger/index.d.ts +2 -0
- package/dist/scheduler/trigger/index.js +1 -0
- package/dist/scheduler/trigger/schedulerTrigger.core.d.ts +22 -1
- package/dist/scheduler/trigger/schedulerTrigger.core.js +69 -6
- package/dist/scheduler/types/index.d.ts +12 -1
- package/dist/scheduler/types/index.js +7 -0
- package/dist/scheduler/types/schedulerTypes.core.d.ts +7 -87
- package/dist/scheduler/types/schedulerTypes.core.js +7 -1
- package/package.json +15 -8
- package/dist/.tsbuildinfo +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/scheduler/clock/index.d.ts.map +0 -1
- package/dist/scheduler/clock/index.js.map +0 -1
- package/dist/scheduler/clock/schedulerClock.type.d.ts.map +0 -1
- package/dist/scheduler/clock/schedulerClock.type.js.map +0 -1
- package/dist/scheduler/constants/index.d.ts.map +0 -1
- package/dist/scheduler/constants/index.js.map +0 -1
- package/dist/scheduler/constants/schedulerConstants.core.d.ts.map +0 -1
- package/dist/scheduler/constants/schedulerConstants.core.js.map +0 -1
- package/dist/scheduler/duration/duration.parser.d.ts.map +0 -1
- package/dist/scheduler/duration/duration.parser.js.map +0 -1
- package/dist/scheduler/duration/index.d.ts.map +0 -1
- package/dist/scheduler/duration/index.js.map +0 -1
- package/dist/scheduler/errors/index.d.ts.map +0 -1
- package/dist/scheduler/errors/index.js.map +0 -1
- package/dist/scheduler/errors/scheduler.errors.d.ts.map +0 -1
- package/dist/scheduler/errors/scheduler.errors.js.map +0 -1
- package/dist/scheduler/executor/index.d.ts.map +0 -1
- package/dist/scheduler/executor/index.js.map +0 -1
- package/dist/scheduler/executor/jobExecutor.core.d.ts.map +0 -1
- package/dist/scheduler/executor/jobExecutor.core.js.map +0 -1
- package/dist/scheduler/job/index.d.ts.map +0 -1
- package/dist/scheduler/job/index.js.map +0 -1
- package/dist/scheduler/job/jobContext.type.d.ts.map +0 -1
- package/dist/scheduler/job/jobContext.type.js.map +0 -1
- package/dist/scheduler/job/jobDefinition.type.d.ts.map +0 -1
- package/dist/scheduler/job/jobDefinition.type.js.map +0 -1
- package/dist/scheduler/job/jobHandler.type.d.ts.map +0 -1
- package/dist/scheduler/job/jobHandler.type.js.map +0 -1
- package/dist/scheduler/job/jobOptions.type.d.ts.map +0 -1
- package/dist/scheduler/job/jobOptions.type.js.map +0 -1
- package/dist/scheduler/priorityQueue/index.d.ts.map +0 -1
- package/dist/scheduler/priorityQueue/index.js.map +0 -1
- package/dist/scheduler/priorityQueue/schedulerPriorityQueue.core.d.ts.map +0 -1
- package/dist/scheduler/priorityQueue/schedulerPriorityQueue.core.js.map +0 -1
- package/dist/scheduler/registry/index.d.ts.map +0 -1
- package/dist/scheduler/registry/index.js.map +0 -1
- package/dist/scheduler/registry/jobRegistry.core.d.ts.map +0 -1
- package/dist/scheduler/registry/jobRegistry.core.js.map +0 -1
- package/dist/scheduler/schedule/index.d.ts.map +0 -1
- package/dist/scheduler/schedule/index.js.map +0 -1
- package/dist/scheduler/schedule/schedule.type.d.ts.map +0 -1
- package/dist/scheduler/schedule/schedule.type.js.map +0 -1
- package/dist/scheduler/schedule/scheduleOptions.type.d.ts.map +0 -1
- package/dist/scheduler/schedule/scheduleOptions.type.js.map +0 -1
- package/dist/scheduler/scheduleHandle/index.d.ts.map +0 -1
- package/dist/scheduler/scheduleHandle/index.js.map +0 -1
- package/dist/scheduler/scheduleHandle/scheduleHandle.type.d.ts.map +0 -1
- package/dist/scheduler/scheduleHandle/scheduleHandle.type.js.map +0 -1
- package/dist/scheduler/scheduler.core.d.ts.map +0 -1
- package/dist/scheduler/scheduler.core.js.map +0 -1
- package/dist/scheduler/trigger/index.d.ts.map +0 -1
- package/dist/scheduler/trigger/index.js.map +0 -1
- package/dist/scheduler/trigger/schedulerTrigger.core.d.ts.map +0 -1
- package/dist/scheduler/trigger/schedulerTrigger.core.js.map +0 -1
- package/dist/scheduler/trigger/trigger.type.d.ts.map +0 -1
- package/dist/scheduler/trigger/trigger.type.js.map +0 -1
- package/dist/scheduler/types/index.d.ts.map +0 -1
- package/dist/scheduler/types/index.js.map +0 -1
- package/dist/scheduler/types/schedulerTypes.core.d.ts.map +0 -1
- package/dist/scheduler/types/schedulerTypes.core.js.map +0 -1
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @zudojs/scheduler
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
In-process scheduling for delayed, recurring and cron-driven jobs.
|
|
4
4
|
|
|
5
5
|
## Installation
|
|
6
6
|
|
|
@@ -11,31 +11,185 @@ npm install @zudojs/scheduler
|
|
|
11
11
|
## Quick Start
|
|
12
12
|
|
|
13
13
|
```typescript
|
|
14
|
-
import {
|
|
14
|
+
import { Scheduler } from "@zudojs/scheduler";
|
|
15
15
|
|
|
16
|
-
const scheduler =
|
|
16
|
+
const scheduler = new Scheduler({
|
|
17
|
+
onError: ({ jobId, error }) => log.error({ jobId, error }, "job failed"),
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
// Register the job, then schedule it. A job must be defined before it can be
|
|
21
|
+
// scheduled — scheduling an unregistered id throws.
|
|
22
|
+
scheduler.define({
|
|
23
|
+
id: "cleanup",
|
|
24
|
+
name: "Clean up old records",
|
|
25
|
+
handler: async (ctx) => {
|
|
26
|
+
await cleanupOldRecords({ signal: ctx.signal });
|
|
27
|
+
},
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
scheduler.cron("0 0 * * *", "cleanup", { timezone: "UTC" });
|
|
31
|
+
|
|
32
|
+
scheduler.start();
|
|
33
|
+
|
|
34
|
+
// On shutdown: aborts in-flight jobs and waits for them to settle.
|
|
35
|
+
await scheduler.stop({ timeoutMs: 30_000 });
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Scheduling
|
|
39
|
+
|
|
40
|
+
Four entry points, each returning a `ScheduleHandle`:
|
|
41
|
+
|
|
42
|
+
```typescript
|
|
43
|
+
scheduler.after("30s", "job-id"); // once, after a delay
|
|
44
|
+
scheduler.at(new Date("2027-01-01"), "job-id"); // once, at an instant
|
|
45
|
+
scheduler.every("5m", "job-id"); // repeating interval
|
|
46
|
+
scheduler.cron("*/15 * * * *", "job-id"); // repeating cron
|
|
47
|
+
```
|
|
17
48
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
49
|
+
Durations accept `ms`, `s`, `m`, `h`, `d` and `w`, and compose: `"1h30m"`.
|
|
50
|
+
Zero, negative and out-of-range durations are rejected.
|
|
51
|
+
|
|
52
|
+
Cron expressions are standard five-field (`minute hour day-of-month month
|
|
53
|
+
day-of-week`) with ranges, lists, steps and three-letter names, plus the
|
|
54
|
+
`@daily`/`@hourly`/`@weekly`/`@monthly`/`@yearly` macros. An invalid expression
|
|
55
|
+
throws where the schedule is declared, not at fire time.
|
|
56
|
+
|
|
57
|
+
Only `timezone: "UTC"` and the system local zone are supported. Any other zone
|
|
58
|
+
is rejected rather than silently ignored — honouring an arbitrary IANA zone
|
|
59
|
+
needs real zone data this package does not carry.
|
|
60
|
+
|
|
61
|
+
## Controlling a schedule
|
|
62
|
+
|
|
63
|
+
The handle is bound to its scheduler, so these reach the queue:
|
|
64
|
+
|
|
65
|
+
```typescript
|
|
66
|
+
const handle = scheduler.every("1h", "sync");
|
|
67
|
+
|
|
68
|
+
handle.nextRun(); // Date — the real next fire time
|
|
69
|
+
await handle.pause(); // stops firing; recomputes from now on resume
|
|
70
|
+
await handle.resume();
|
|
71
|
+
await handle.cancel(); // aborts any in-flight run and removes the schedule
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Failure handling
|
|
75
|
+
|
|
76
|
+
Nothing is swallowed. A job that throws is reported to `onError`, after its
|
|
77
|
+
retry policy is exhausted:
|
|
78
|
+
|
|
79
|
+
```typescript
|
|
80
|
+
scheduler.define({
|
|
81
|
+
id: "flaky",
|
|
82
|
+
name: "Flaky upstream call",
|
|
83
|
+
options: {
|
|
84
|
+
timeout: 10_000,
|
|
85
|
+
retry: {
|
|
86
|
+
attempts: 3,
|
|
87
|
+
strategy: "exponential", // or "fixed" | "linear"
|
|
88
|
+
delay: 1_000,
|
|
89
|
+
maxDelay: 30_000,
|
|
90
|
+
jitter: true,
|
|
91
|
+
},
|
|
22
92
|
},
|
|
93
|
+
handler: callUpstream,
|
|
94
|
+
});
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
A timeout raises `SchedulerJobTimeoutError` and **aborts the handler** via
|
|
98
|
+
`ctx.signal`; anything else raises `SchedulerJobExecutionError` carrying the
|
|
99
|
+
original error as `cause`.
|
|
100
|
+
|
|
101
|
+
## Concurrency and overlap
|
|
102
|
+
|
|
103
|
+
`maxConcurrency` (default 10) bounds executions in flight across all schedules;
|
|
104
|
+
work over the ceiling waits for the next tick. Per schedule, `overlap` decides
|
|
105
|
+
what happens when a fire time arrives while the previous run is still going:
|
|
106
|
+
|
|
107
|
+
```typescript
|
|
108
|
+
scheduler.every("10s", "report", { overlap: "skip" });
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
| `overlap` | Behaviour when the previous run is still going |
|
|
112
|
+
| ------------------- | ----------------------------------------------- |
|
|
113
|
+
| `"allow"` (default) | starts the new run alongside it |
|
|
114
|
+
| `"skip"` | drops the fire time |
|
|
115
|
+
| `"queue"` | holds it and runs it when the current one ends |
|
|
116
|
+
| `"replace"` | aborts the running execution and starts a new one |
|
|
117
|
+
|
|
118
|
+
`JobOptions.overlap` sets the default for every schedule of a job;
|
|
119
|
+
`ScheduleOptions.overlap` overrides it per schedule.
|
|
120
|
+
|
|
121
|
+
`JobOptions.concurrency` caps how many executions of one job run at once
|
|
122
|
+
across every schedule that fires it. A fire time arriving at the ceiling is
|
|
123
|
+
held and dispatched when an execution finishes, not dropped:
|
|
124
|
+
|
|
125
|
+
```typescript
|
|
126
|
+
scheduler.define({
|
|
127
|
+
id: "reindex",
|
|
128
|
+
name: "Reindex a tenant",
|
|
129
|
+
options: { concurrency: 2 },
|
|
130
|
+
handler: reindex,
|
|
23
131
|
});
|
|
132
|
+
```
|
|
24
133
|
|
|
25
|
-
|
|
134
|
+
`ScheduleOptions.priority` breaks ties between schedules due at the same
|
|
135
|
+
instant — higher runs first. It never lets a schedule jump ahead of one due
|
|
136
|
+
earlier.
|
|
137
|
+
|
|
138
|
+
## Misfires
|
|
139
|
+
|
|
140
|
+
A fire time already in the past follows the schedule's `misfire` policy. This
|
|
141
|
+
is the case for `at(pastDate)`, for a schedule restored after a restart, and
|
|
142
|
+
for a recurring schedule whose process was blocked past its fire time.
|
|
143
|
+
|
|
144
|
+
| `misfire` | Behaviour |
|
|
145
|
+
| ---------------------- | ---------------------------------------------------- |
|
|
146
|
+
| `"run-once"` (default) | runs once immediately, then resumes from now |
|
|
147
|
+
| `"skip"` | refuses the schedule |
|
|
148
|
+
| `"catch-up"` | replays every missed occurrence until it is current |
|
|
149
|
+
|
|
150
|
+
```typescript
|
|
151
|
+
scheduler.every("1h", "hourly-rollup", { misfire: "catch-up" });
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
## Execution history
|
|
155
|
+
|
|
156
|
+
The scheduler keeps the last 100 executions (`MAX_EXECUTION_HISTORY`), each a
|
|
157
|
+
`JobExecution` with its status, timings and error:
|
|
158
|
+
|
|
159
|
+
```typescript
|
|
160
|
+
scheduler.getExecutions("cleanup");
|
|
161
|
+
// [{ id, jobId, scheduleId, status: "completed" | "failed" | "timed_out" |
|
|
162
|
+
// "cancelled" | "running", scheduledAt, startedAt, completedAt,
|
|
163
|
+
// duration, attempt, error? }]
|
|
26
164
|
```
|
|
27
165
|
|
|
28
166
|
## Features
|
|
29
167
|
|
|
30
|
-
-
|
|
31
|
-
-
|
|
32
|
-
-
|
|
33
|
-
-
|
|
34
|
-
-
|
|
168
|
+
- Delay, date, interval and cron triggers
|
|
169
|
+
- Real five-field cron parsing with macros, ranges, steps and names
|
|
170
|
+
- Bound schedule handles: pause, resume, cancel, next-run
|
|
171
|
+
- Retry policies with fixed, linear and exponential backoff, capping and jitter
|
|
172
|
+
- Per-job timeouts that abort the handler through `AbortSignal`
|
|
173
|
+
- Global concurrency ceiling, per-job concurrency limits, and per-schedule
|
|
174
|
+
overlap and misfire policies
|
|
175
|
+
- Bounded execution history
|
|
176
|
+
- Graceful shutdown with abort or drain
|
|
177
|
+
- Min-heap priority queue, O(log n) insert and remove
|
|
178
|
+
|
|
179
|
+
## Not included
|
|
180
|
+
|
|
181
|
+
This package schedules work inside one process. It has no persistence, no
|
|
182
|
+
cross-process locking and no worker pool — a restart loses the schedule, and two
|
|
183
|
+
instances will each run the same job. Pair it with `@zudojs/queue` when you need
|
|
184
|
+
durability or distribution.
|
|
185
|
+
|
|
186
|
+
Because there is no store and no lock, the store, lock, not-started and
|
|
187
|
+
schedule-lookup error classes are not re-exported here; they live in
|
|
188
|
+
`@zudojs/errors` for a durable scheduler built on top.
|
|
35
189
|
|
|
36
190
|
## Use Cases
|
|
37
191
|
|
|
38
|
-
- Scheduled maintenance
|
|
192
|
+
- Scheduled maintenance and cleanup
|
|
193
|
+
- Periodic synchronisation
|
|
39
194
|
- Report generation
|
|
40
|
-
-
|
|
41
|
-
- Periodic synchronization
|
|
195
|
+
- Cache warming and refresh
|
package/dist/index.d.ts
CHANGED
|
@@ -24,17 +24,21 @@
|
|
|
24
24
|
* ```
|
|
25
25
|
*/
|
|
26
26
|
export type { SchedulerJobId, ScheduleId, ExecutionId, ScheduleType, ScheduleState, JobState, OverlapPolicy, MisfirePolicy, RetryStrategy, RetryPolicy, JobOptions, JobDefinition, JobHandler, JobContext, JobExecution, JobExecutionResult, Schedule, ScheduleOptions, ScheduleHandle, Trigger, } from "./scheduler/types/index.js";
|
|
27
|
-
export { DEFAULT_JOB_TIMEOUT, DEFAULT_MAX_CONCURRENCY, DEFAULT_MAX_RETRIES, DEFAULT_RETRY_DELAY, MAX_TIMER_DELAY, MAX_JOBS, MAX_SCHEDULES, MAX_EXECUTION_HISTORY, DEFAULT_MISFIRE_POLICY, DEFAULT_OVERLAP_POLICY,
|
|
27
|
+
export { DEFAULT_JOB_TIMEOUT, DEFAULT_MAX_CONCURRENCY, DEFAULT_MAX_RETRIES, DEFAULT_RETRY_DELAY, MAX_TIMER_DELAY, MAX_JOBS, MAX_SCHEDULES, MAX_EXECUTION_HISTORY, DEFAULT_MISFIRE_POLICY, DEFAULT_OVERLAP_POLICY, } from "./scheduler/constants/index.js";
|
|
28
28
|
export type { SchedulerErrorOptions } from "./scheduler/errors/index.js";
|
|
29
|
-
export { SchedulerError,
|
|
29
|
+
export { SchedulerError, SchedulerAlreadyStartedError, SchedulerStoppedError, SchedulerJobNotFoundError, SchedulerJobAlreadyExistsError, InvalidJobError, InvalidScheduleError, CronParseError, InvalidDurationError, SchedulerJobExecutionError, SchedulerJobTimeoutError, SchedulerJobCancelledError, createSchedulerError, isSchedulerError, } from "./scheduler/errors/index.js";
|
|
30
30
|
export { createJobContext, createJobDefinition, } from "./scheduler/job/index.js";
|
|
31
31
|
export { createSchedule } from "./scheduler/schedule/index.js";
|
|
32
32
|
export { ScheduleHandleImpl } from "./scheduler/scheduleHandle/index.js";
|
|
33
|
+
export type { ScheduleHandleBinding } from "./scheduler/scheduleHandle/index.js";
|
|
33
34
|
export { DateTrigger, DelayTrigger, IntervalTrigger, CronTrigger, } from "./scheduler/trigger/index.js";
|
|
35
|
+
export { parseCron, nextCronDate } from "./scheduler/trigger/index.js";
|
|
36
|
+
export type { ParsedCron } from "./scheduler/trigger/index.js";
|
|
34
37
|
export { SystemClock, createSystemClock } from "./scheduler/clock/index.js";
|
|
35
38
|
export { JobRegistry } from "./scheduler/registry/index.js";
|
|
36
|
-
export { JobExecutor } from "./scheduler/executor/index.js";
|
|
39
|
+
export { JobExecutor, retryDelay } from "./scheduler/executor/index.js";
|
|
37
40
|
export { PriorityQueue } from "./scheduler/priorityQueue/index.js";
|
|
38
41
|
export { parseDuration } from "./scheduler/duration/index.js";
|
|
39
42
|
export { Scheduler } from "./scheduler/scheduler.core.js";
|
|
43
|
+
export type { SchedulerOptions, SchedulerErrorEvent, } from "./scheduler/scheduler.core.js";
|
|
40
44
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.js
CHANGED
|
@@ -24,8 +24,8 @@
|
|
|
24
24
|
* ```
|
|
25
25
|
*/
|
|
26
26
|
// Constants
|
|
27
|
-
export { DEFAULT_JOB_TIMEOUT, DEFAULT_MAX_CONCURRENCY, DEFAULT_MAX_RETRIES, DEFAULT_RETRY_DELAY, MAX_TIMER_DELAY, MAX_JOBS, MAX_SCHEDULES, MAX_EXECUTION_HISTORY, DEFAULT_MISFIRE_POLICY, DEFAULT_OVERLAP_POLICY,
|
|
28
|
-
export { SchedulerError,
|
|
27
|
+
export { DEFAULT_JOB_TIMEOUT, DEFAULT_MAX_CONCURRENCY, DEFAULT_MAX_RETRIES, DEFAULT_RETRY_DELAY, MAX_TIMER_DELAY, MAX_JOBS, MAX_SCHEDULES, MAX_EXECUTION_HISTORY, DEFAULT_MISFIRE_POLICY, DEFAULT_OVERLAP_POLICY, } from "./scheduler/constants/index.js";
|
|
28
|
+
export { SchedulerError, SchedulerAlreadyStartedError, SchedulerStoppedError, SchedulerJobNotFoundError, SchedulerJobAlreadyExistsError, InvalidJobError, InvalidScheduleError, CronParseError, InvalidDurationError, SchedulerJobExecutionError, SchedulerJobTimeoutError, SchedulerJobCancelledError, createSchedulerError, isSchedulerError, } from "./scheduler/errors/index.js";
|
|
29
29
|
// Job
|
|
30
30
|
export { createJobContext, createJobDefinition, } from "./scheduler/job/index.js";
|
|
31
31
|
// Schedule
|
|
@@ -34,12 +34,13 @@ export { createSchedule } from "./scheduler/schedule/index.js";
|
|
|
34
34
|
export { ScheduleHandleImpl } from "./scheduler/scheduleHandle/index.js";
|
|
35
35
|
// Trigger
|
|
36
36
|
export { DateTrigger, DelayTrigger, IntervalTrigger, CronTrigger, } from "./scheduler/trigger/index.js";
|
|
37
|
+
export { parseCron, nextCronDate } from "./scheduler/trigger/index.js";
|
|
37
38
|
// Clock
|
|
38
39
|
export { SystemClock, createSystemClock } from "./scheduler/clock/index.js";
|
|
39
40
|
// Registry
|
|
40
41
|
export { JobRegistry } from "./scheduler/registry/index.js";
|
|
41
42
|
// Executor
|
|
42
|
-
export { JobExecutor } from "./scheduler/executor/index.js";
|
|
43
|
+
export { JobExecutor, retryDelay } from "./scheduler/executor/index.js";
|
|
43
44
|
// Priority Queue
|
|
44
45
|
export { PriorityQueue } from "./scheduler/priorityQueue/index.js";
|
|
45
46
|
// Duration
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { DEFAULT_JOB_TIMEOUT, DEFAULT_MAX_CONCURRENCY, DEFAULT_MAX_RETRIES, DEFAULT_RETRY_DELAY, MAX_TIMER_DELAY, MAX_JOBS, MAX_SCHEDULES, MAX_EXECUTION_HISTORY, DEFAULT_MISFIRE_POLICY, DEFAULT_OVERLAP_POLICY,
|
|
1
|
+
export { DEFAULT_JOB_TIMEOUT, DEFAULT_MAX_CONCURRENCY, DEFAULT_MAX_RETRIES, DEFAULT_RETRY_DELAY, MAX_TIMER_DELAY, MAX_JOBS, MAX_SCHEDULES, MAX_EXECUTION_HISTORY, DEFAULT_MISFIRE_POLICY, DEFAULT_OVERLAP_POLICY, } from "./schedulerConstants.core.js";
|
|
2
2
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { DEFAULT_JOB_TIMEOUT, DEFAULT_MAX_CONCURRENCY, DEFAULT_MAX_RETRIES, DEFAULT_RETRY_DELAY, MAX_TIMER_DELAY, MAX_JOBS, MAX_SCHEDULES, MAX_EXECUTION_HISTORY, DEFAULT_MISFIRE_POLICY, DEFAULT_OVERLAP_POLICY,
|
|
1
|
+
export { DEFAULT_JOB_TIMEOUT, DEFAULT_MAX_CONCURRENCY, DEFAULT_MAX_RETRIES, DEFAULT_RETRY_DELAY, MAX_TIMER_DELAY, MAX_JOBS, MAX_SCHEDULES, MAX_EXECUTION_HISTORY, DEFAULT_MISFIRE_POLICY, DEFAULT_OVERLAP_POLICY, } from "./schedulerConstants.core.js";
|
|
2
2
|
//# sourceMappingURL=index.js.map
|
|
@@ -45,8 +45,4 @@ export declare const DEFAULT_MISFIRE_POLICY: MisfirePolicy;
|
|
|
45
45
|
* Default overlap policy.
|
|
46
46
|
*/
|
|
47
47
|
export declare const DEFAULT_OVERLAP_POLICY: OverlapPolicy;
|
|
48
|
-
/**
|
|
49
|
-
* Tick interval for the scheduler timer (1 second).
|
|
50
|
-
*/
|
|
51
|
-
export declare const SCHEDULER_TICK_INTERVAL = 1000;
|
|
52
48
|
//# sourceMappingURL=schedulerConstants.core.d.ts.map
|
|
@@ -43,8 +43,4 @@ export const DEFAULT_MISFIRE_POLICY = "run-once";
|
|
|
43
43
|
* Default overlap policy.
|
|
44
44
|
*/
|
|
45
45
|
export const DEFAULT_OVERLAP_POLICY = "allow";
|
|
46
|
-
/**
|
|
47
|
-
* Tick interval for the scheduler timer (1 second).
|
|
48
|
-
*/
|
|
49
|
-
export const SCHEDULER_TICK_INTERVAL = 1_000;
|
|
50
46
|
//# sourceMappingURL=schedulerConstants.core.js.map
|
|
@@ -1,11 +1,19 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Parses a human-readable duration string into milliseconds.
|
|
3
3
|
*
|
|
4
|
-
* Supported
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
4
|
+
* Supported units: `ms`, `s`, `m`, `h`, `d`, `w`. Components may be combined
|
|
5
|
+
* (`"1h30m"`), and each must be a non-negative integer. The total must be
|
|
6
|
+
* greater than zero — a zero duration would schedule a job that fires
|
|
7
|
+
* continuously — and within roughly a century.
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* parseDuration("5s") // 5000
|
|
11
|
+
* parseDuration("1h30m") // 5400000
|
|
12
|
+
* parseDuration("250ms") // 250
|
|
13
|
+
*
|
|
14
|
+
* @param duration - The duration string.
|
|
15
|
+
* @returns The duration in milliseconds.
|
|
16
|
+
* @throws {InvalidDurationError} when the string is malformed or out of range.
|
|
9
17
|
*/
|
|
10
18
|
export declare function parseDuration(duration: string): number;
|
|
11
19
|
//# sourceMappingURL=duration.parser.d.ts.map
|
|
@@ -1,31 +1,66 @@
|
|
|
1
1
|
import { InvalidDurationError } from "../errors/scheduler.errors.js";
|
|
2
|
+
/**
|
|
3
|
+
* Largest duration that can safely be added to "now" and still produce a valid
|
|
4
|
+
* Date. Beyond this the result is an Invalid Date whose `getTime()` is `NaN`,
|
|
5
|
+
* and every heap comparison against `NaN` is false — so the entry never sinks
|
|
6
|
+
* and parks itself at the head of the queue, blocking everything behind it.
|
|
7
|
+
*/
|
|
8
|
+
const MAX_DURATION_MS = 100 * 365 * 24 * 60 * 60 * 1000; // ~100 years
|
|
9
|
+
/** Milliseconds per supported unit. */
|
|
10
|
+
const UNIT_MS = {
|
|
11
|
+
ms: 1,
|
|
12
|
+
s: 1000,
|
|
13
|
+
m: 60 * 1000,
|
|
14
|
+
h: 60 * 60 * 1000,
|
|
15
|
+
d: 24 * 60 * 60 * 1000,
|
|
16
|
+
w: 7 * 24 * 60 * 60 * 1000,
|
|
17
|
+
};
|
|
2
18
|
/**
|
|
3
19
|
* Parses a human-readable duration string into milliseconds.
|
|
4
20
|
*
|
|
5
|
-
* Supported
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
21
|
+
* Supported units: `ms`, `s`, `m`, `h`, `d`, `w`. Components may be combined
|
|
22
|
+
* (`"1h30m"`), and each must be a non-negative integer. The total must be
|
|
23
|
+
* greater than zero — a zero duration would schedule a job that fires
|
|
24
|
+
* continuously — and within roughly a century.
|
|
25
|
+
*
|
|
26
|
+
* @example
|
|
27
|
+
* parseDuration("5s") // 5000
|
|
28
|
+
* parseDuration("1h30m") // 5400000
|
|
29
|
+
* parseDuration("250ms") // 250
|
|
30
|
+
*
|
|
31
|
+
* @param duration - The duration string.
|
|
32
|
+
* @returns The duration in milliseconds.
|
|
33
|
+
* @throws {InvalidDurationError} when the string is malformed or out of range.
|
|
10
34
|
*/
|
|
11
35
|
export function parseDuration(duration) {
|
|
12
|
-
const
|
|
13
|
-
if (
|
|
36
|
+
const trimmed = duration.trim();
|
|
37
|
+
if (trimmed.length === 0) {
|
|
14
38
|
throw new InvalidDurationError(duration);
|
|
15
39
|
}
|
|
16
|
-
|
|
17
|
-
const
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
40
|
+
// Each component is digits followed by a unit. `ms` is matched before `m`.
|
|
41
|
+
const pattern = /(\d+)(ms|s|m|h|d|w)/gy;
|
|
42
|
+
let total = 0;
|
|
43
|
+
let matched = 0;
|
|
44
|
+
let match;
|
|
45
|
+
while ((match = pattern.exec(trimmed)) !== null) {
|
|
46
|
+
const amount = Number(match[1]);
|
|
47
|
+
const unit = match[2];
|
|
48
|
+
if (!Number.isSafeInteger(amount)) {
|
|
49
|
+
throw new InvalidDurationError(duration);
|
|
50
|
+
}
|
|
51
|
+
total += amount * UNIT_MS[unit];
|
|
52
|
+
matched = pattern.lastIndex;
|
|
53
|
+
if (total > MAX_DURATION_MS) {
|
|
28
54
|
throw new InvalidDurationError(duration);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
// Anything left over means the string was not fully consumed.
|
|
58
|
+
if (matched !== trimmed.length) {
|
|
59
|
+
throw new InvalidDurationError(duration);
|
|
60
|
+
}
|
|
61
|
+
if (total <= 0) {
|
|
62
|
+
throw new InvalidDurationError(duration);
|
|
29
63
|
}
|
|
64
|
+
return total;
|
|
30
65
|
}
|
|
31
66
|
//# sourceMappingURL=duration.parser.js.map
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export { SchedulerError,
|
|
1
|
+
export { SchedulerError, SchedulerAlreadyStartedError, SchedulerStoppedError, SchedulerJobNotFoundError, SchedulerJobAlreadyExistsError, InvalidJobError, InvalidScheduleError, CronParseError, InvalidDurationError, SchedulerJobExecutionError, SchedulerJobTimeoutError, SchedulerJobCancelledError, createSchedulerError, isSchedulerError, } from "./scheduler.errors.js";
|
|
2
2
|
export type { SchedulerErrorOptions } from "./scheduler.errors.js";
|
|
3
3
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { SchedulerError,
|
|
1
|
+
export { SchedulerError, SchedulerAlreadyStartedError, SchedulerStoppedError, SchedulerJobNotFoundError, SchedulerJobAlreadyExistsError, InvalidJobError, InvalidScheduleError, CronParseError, InvalidDurationError, SchedulerJobExecutionError, SchedulerJobTimeoutError, SchedulerJobCancelledError, createSchedulerError, isSchedulerError, } from "./scheduler.errors.js";
|
|
2
2
|
//# sourceMappingURL=index.js.map
|
|
@@ -4,7 +4,13 @@
|
|
|
4
4
|
* Scheduler-specific error classes for the Zudojs framework.
|
|
5
5
|
*
|
|
6
6
|
* Re-exported from @zudojs/errors for convenience.
|
|
7
|
+
*
|
|
8
|
+
* Only the classes this package can actually raise are re-exported. The
|
|
9
|
+
* store, lock, not-started and schedule-lookup errors were re-exported here
|
|
10
|
+
* too, and nothing in an in-process scheduler with no persistence and no
|
|
11
|
+
* cross-process locking could ever throw one. They remain available from
|
|
12
|
+
* @zudojs/errors for a durable scheduler built on top.
|
|
7
13
|
*/
|
|
8
|
-
export { SchedulerError,
|
|
14
|
+
export { SchedulerError, SchedulerAlreadyStartedError, SchedulerStoppedError, SchedulerJobNotFoundError, SchedulerJobAlreadyExistsError, InvalidJobError, InvalidScheduleError, CronParseError, InvalidDurationError, SchedulerJobExecutionError, SchedulerJobTimeoutError, SchedulerJobCancelledError, createSchedulerError, isSchedulerError, } from "@zudojs/errors";
|
|
9
15
|
export type { SchedulerErrorOptions } from "@zudojs/errors";
|
|
10
16
|
//# sourceMappingURL=scheduler.errors.d.ts.map
|
|
@@ -4,6 +4,12 @@
|
|
|
4
4
|
* Scheduler-specific error classes for the Zudojs framework.
|
|
5
5
|
*
|
|
6
6
|
* Re-exported from @zudojs/errors for convenience.
|
|
7
|
+
*
|
|
8
|
+
* Only the classes this package can actually raise are re-exported. The
|
|
9
|
+
* store, lock, not-started and schedule-lookup errors were re-exported here
|
|
10
|
+
* too, and nothing in an in-process scheduler with no persistence and no
|
|
11
|
+
* cross-process locking could ever throw one. They remain available from
|
|
12
|
+
* @zudojs/errors for a durable scheduler built on top.
|
|
7
13
|
*/
|
|
8
|
-
export { SchedulerError,
|
|
14
|
+
export { SchedulerError, SchedulerAlreadyStartedError, SchedulerStoppedError, SchedulerJobNotFoundError, SchedulerJobAlreadyExistsError, InvalidJobError, InvalidScheduleError, CronParseError, InvalidDurationError, SchedulerJobExecutionError, SchedulerJobTimeoutError, SchedulerJobCancelledError, createSchedulerError, isSchedulerError, } from "@zudojs/errors";
|
|
9
15
|
//# sourceMappingURL=scheduler.errors.js.map
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { JobExecutor } from "./jobExecutor.core.js";
|
|
1
|
+
export { JobExecutor, retryDelay } from "./jobExecutor.core.js";
|
|
2
2
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { JobExecutor } from "./jobExecutor.core.js";
|
|
1
|
+
export { JobExecutor, retryDelay } from "./jobExecutor.core.js";
|
|
2
2
|
//# sourceMappingURL=index.js.map
|
|
@@ -1,19 +1,39 @@
|
|
|
1
1
|
import type { JobDefinition } from "../job/jobDefinition.type.js";
|
|
2
|
+
import type { RetryPolicy } from "../job/jobOptions.type.js";
|
|
2
3
|
import type { JobExecutionResult } from "../types/schedulerTypes.core.js";
|
|
3
4
|
import type { Clock } from "../clock/schedulerClock.type.js";
|
|
4
5
|
/**
|
|
5
|
-
* Executes a job with timeout support.
|
|
6
|
+
* Executes a job with timeout, cancellation and retry support.
|
|
6
7
|
*/
|
|
7
8
|
export declare class JobExecutor {
|
|
8
9
|
private readonly clock;
|
|
9
10
|
constructor(clock: Clock);
|
|
10
11
|
/**
|
|
11
|
-
* Executes a job.
|
|
12
|
+
* Executes a job, retrying according to its retry policy.
|
|
13
|
+
*
|
|
14
|
+
* @param job - The job definition.
|
|
15
|
+
* @param executionId - Identifier for this execution.
|
|
16
|
+
* @param scheduledAt - The time the job was scheduled to run.
|
|
17
|
+
* @param attempt - The attempt number to start from (1-based).
|
|
18
|
+
* @param signal - Signal that aborts the job and stops further retries.
|
|
19
|
+
* @param data - Optional payload handed to the handler.
|
|
20
|
+
* @returns The execution result.
|
|
12
21
|
*/
|
|
13
|
-
execute(job: JobDefinition, executionId: string, scheduledAt: Date, attempt: number, signal: AbortSignal): Promise<JobExecutionResult>;
|
|
22
|
+
execute(job: JobDefinition, executionId: string, scheduledAt: Date, attempt: number, signal: AbortSignal, data?: unknown): Promise<JobExecutionResult>;
|
|
23
|
+
/** Runs the handler once, under a timeout that also aborts it. */
|
|
24
|
+
private runOnce;
|
|
25
|
+
/** Maps a thrown value onto the scheduler's error taxonomy. */
|
|
26
|
+
private classify;
|
|
14
27
|
/**
|
|
15
|
-
* Wraps
|
|
28
|
+
* Wraps an operation with a timeout that aborts it.
|
|
16
29
|
*/
|
|
17
30
|
private withTimeout;
|
|
18
31
|
}
|
|
32
|
+
/**
|
|
33
|
+
* Computes the delay before the next retry attempt.
|
|
34
|
+
*
|
|
35
|
+
* `RetryPolicy` has carried strategy, delay, maxDelay and jitter since the
|
|
36
|
+
* package was written; none of it was ever applied.
|
|
37
|
+
*/
|
|
38
|
+
export declare function retryDelay(policy: RetryPolicy | undefined, attempt: number): number;
|
|
19
39
|
//# sourceMappingURL=jobExecutor.core.d.ts.map
|