@warlock.js/scheduler 5.23.2 → 5.25.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/CHANGELOG.md +125 -113
- package/cjs/index.cjs +49 -3
- package/cjs/index.cjs.map +1 -1
- package/esm/process-roles.mjs +37 -0
- package/esm/process-roles.mjs.map +1 -0
- package/esm/scheduler.d.mts +9 -2
- package/esm/scheduler.d.mts.map +1 -1
- package/esm/scheduler.mjs +15 -3
- package/esm/scheduler.mjs.map +1 -1
- package/llms-full.txt +683 -683
- package/package.json +2 -2
- package/skills/configure-retry-and-overlap/SKILL.md +152 -152
- package/skills/observe-scheduler/SKILL.md +153 -153
- package/skills/pin-schedule-timezone/SKILL.md +114 -114
- package/skills/schedule-fluently/SKILL.md +141 -141
- package/skills/schedule-with-cron/SKILL.md +123 -123
package/CHANGELOG.md
CHANGED
|
@@ -1,9 +1,21 @@
|
|
|
1
|
-
# Changelog — @warlock.js/scheduler
|
|
2
|
-
|
|
3
|
-
All notable changes to `@warlock.js/scheduler` are documented in this file.
|
|
4
|
-
|
|
5
|
-
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). `@warlock.js/*` packages are released in lockstep — every package shares the same version number, so a version below may list only the changes that affected this package.
|
|
6
|
-
|
|
1
|
+
# Changelog — @warlock.js/scheduler
|
|
2
|
+
|
|
3
|
+
All notable changes to `@warlock.js/scheduler` are documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). `@warlock.js/*` packages are released in lockstep — every package shares the same version number, so a version below may list only the changes that affected this package.
|
|
6
|
+
|
|
7
|
+
## 5.25.0 - 2026-09-28
|
|
8
|
+
|
|
9
|
+
### Changed
|
|
10
|
+
|
|
11
|
+
- `scheduler.start()` is now a no-op, logging `scheduler: not started (role: ...)`, on a process that doesn't serve the `worker` role (`WARLOCK_ROLES`) — so an app calling it in `main.ts` doesn't run its jobs on every `web`/`api` node. The "jobs registered but `start()` never called" development warning no longer fires on such a process. With no `--role` passed, every role is on and nothing changes.
|
|
12
|
+
|
|
13
|
+
## 5.24.0 - 2026-09-27
|
|
14
|
+
|
|
15
|
+
### Changed
|
|
16
|
+
|
|
17
|
+
- Lockstep release; package APIs are unchanged.
|
|
18
|
+
|
|
7
19
|
## 5.23.2 - 2026-09-26
|
|
8
20
|
|
|
9
21
|
### Changed
|
|
@@ -16,110 +28,110 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
|
|
|
16
28
|
|
|
17
29
|
- Lockstep patch release; package APIs are unchanged.
|
|
18
30
|
|
|
19
|
-
## 5.23.0 - 2026-09-25
|
|
20
|
-
|
|
21
|
-
### Added
|
|
22
|
-
|
|
23
|
-
- `scheduler.around((job, run) => …)` wraps every job callback execution, each retry attempt included, so jobs can run inside a context such as `AsyncLocalStorage`. Multiple hooks compose with the first registered outermost; the call returns an unsubscribe function. A hook that never calls `run` skips the execution and emits `job:skip` (`JobResult.skipped` / `skipReason`); a hook that throws follows the normal retry/error path.
|
|
24
|
-
|
|
25
|
-
## 5.22.1 - 2026-09-25
|
|
26
|
-
|
|
27
|
-
### Changed
|
|
28
|
-
|
|
29
|
-
- Lockstep patch release; package APIs are unchanged.
|
|
30
|
-
|
|
31
|
-
## 5.22.0 - 2026-09-25
|
|
32
|
-
|
|
33
|
-
### Fixed
|
|
34
|
-
|
|
35
|
-
- Cron and time parsing handle absent fields explicitly under strict TypeScript checks.
|
|
36
|
-
|
|
37
|
-
## 5.21.0 - 2026-09-25
|
|
38
|
-
|
|
39
|
-
### Changed
|
|
40
|
-
|
|
41
|
-
- Lockstep release maintenance and dependency refresh.
|
|
42
|
-
## 5.20.0 - 2026-09-24
|
|
43
|
-
|
|
44
|
-
### Added
|
|
45
|
-
|
|
46
|
-
- `job.onOneServer({ lockTtl?, key? })` — run each tick on exactly one server. Every server races for a create-only, TTL-bounded cache claim keyed `scheduler.<key ?? name>.<scheduledTickEpochMs>`. The claim is never released, so exactly one server runs each tick even if another server's timer fires late. Losers skip the tick and emit `job:skip`. Requires a shared cache driver (redis/pg) and a job name or `key`. `@warlock.js/cache` is an optional peer dependency. Default claim TTL is `min(interval, 1h)` with a 60s floor (1h for cron jobs).
|
|
47
|
-
|
|
48
|
-
## 5.19.0 - 2026-09-23
|
|
49
|
-
|
|
50
|
-
### Changed
|
|
51
|
-
|
|
52
|
-
- Refined package skill-discovery descriptions and regenerated the llms projections.
|
|
53
|
-
|
|
54
|
-
## 5.11.0 - 2026-09-14
|
|
55
|
-
|
|
56
|
-
_Released in lockstep with the `@warlock.js/*` family; no package-specific changes in 5.11.0._
|
|
57
|
-
|
|
58
|
-
## 5.10.0 - 2026-09-14
|
|
59
|
-
|
|
60
|
-
_Released in lockstep with the `@warlock.js/*` family; no package-specific changes in 5.10.0._
|
|
61
|
-
|
|
62
|
-
## 5.9.0 - 2026-09-13
|
|
63
|
-
|
|
64
|
-
_Released in lockstep with the `@warlock.js/*` family; no package-specific changes in 5.9.0._
|
|
65
|
-
|
|
66
|
-
## 5.5.0 - 2026-09-07
|
|
67
|
-
|
|
68
|
-
### Fixed
|
|
69
|
-
|
|
70
|
-
- Documentation shipped in this package's `skills/` told users to run `pnpm`-specific commands. `pnpm <binary>` has no npm equivalent, so those instructions failed outright for anyone not using pnpm. Commands are now package-manager neutral.
|
|
71
|
-
|
|
72
|
-
## 5.2.3 - 2026-09-02
|
|
73
|
-
|
|
74
|
-
### Fixed
|
|
75
|
-
|
|
76
|
-
- Released in exact lockstep with Core's Web generator repairs so every family dependency remains installable at 5.2.3.
|
|
77
|
-
|
|
78
|
-
## 5.2.2
|
|
79
|
-
|
|
80
|
-
- Documented: the README, CHANGELOG, and `overview` skill now describe the
|
|
81
|
-
already-shipped `package.json` `"warlock": { "environment": "server" }`
|
|
82
|
-
marker — `@warlock.js/scheduler`'s entire runtime surface is server-only.
|
|
83
|
-
The marker is build-boundary metadata read by `@warlock.js/web`'s Gate A
|
|
84
|
-
(import resolution) and Gate C (emitted-bundle verification); app client
|
|
85
|
-
code must not value-import this package, type-only imports are allowed, and
|
|
86
|
-
server loaders/controllers/modules may import it freely. No source change.
|
|
87
|
-
|
|
88
|
-
## 5.1.0
|
|
89
|
-
|
|
90
|
-
No changes to `@warlock.js/scheduler`. Released in lockstep with the `@warlock.js/web`
|
|
91
|
-
React-execution fix and the `@warlock.js/core` CLI additions — see those packages'
|
|
92
|
-
changelogs.
|
|
93
|
-
|
|
94
|
-
## 5.0.2 - 2026-08-25
|
|
95
|
-
|
|
96
|
-
No changes to `@warlock.js/scheduler`. Released in lockstep with the `@warlock.js/web` SSR
|
|
97
|
-
fix (`ssr.noExternal`) — see that package's changelog.
|
|
98
|
-
|
|
99
|
-
## 5.0.1 - 2026-08-25
|
|
100
|
-
|
|
101
|
-
No changes to `@warlock.js/scheduler`. Released in lockstep with the `create-warlock` vite
|
|
102
|
-
resolution pin and the `@warlock.js/web` peer narrowing — see those packages'
|
|
103
|
-
changelogs.
|
|
104
|
-
|
|
105
|
-
## 5.0.0 - 2026-08-25
|
|
106
|
-
|
|
107
|
-
### Changed
|
|
108
|
-
|
|
109
|
-
- This package is unchanged in 5.0.0; its version moved only because the Warlock family releases in lockstep.
|
|
110
|
-
|
|
111
|
-
## 4.12.0
|
|
112
|
-
|
|
113
|
-
### Changed
|
|
114
|
-
|
|
115
|
-
- Declares its own test runner and pins it to an exact version (`vitest@4.1.10`). The package is its own repository, so a runner resolved from a workspace root it may not be cloned with is a runner it cannot rely on. The pin is exact rather than a range because the version moved underneath the suite mid-development on an unrelated install — a suite whose runner can change without anyone choosing it proves less than it appears to
|
|
116
|
-
|
|
117
|
-
## 4.6.0
|
|
118
|
-
|
|
119
|
-
### Fixed
|
|
120
|
-
|
|
121
|
-
- Warn in development when jobs are registered but `start()` is never called — a one-shot deferred check logs `N job(s) registered but scheduler.start() was never called`, is suppressed once `start()` runs or in production (`NODE_ENV=production`), and is unref'd so it never holds the process open.
|
|
122
|
-
|
|
123
|
-
## 4.1.15
|
|
124
|
-
|
|
125
|
-
- Baseline — per-package changelog tracking starts at this version.
|
|
31
|
+
## 5.23.0 - 2026-09-25
|
|
32
|
+
|
|
33
|
+
### Added
|
|
34
|
+
|
|
35
|
+
- `scheduler.around((job, run) => …)` wraps every job callback execution, each retry attempt included, so jobs can run inside a context such as `AsyncLocalStorage`. Multiple hooks compose with the first registered outermost; the call returns an unsubscribe function. A hook that never calls `run` skips the execution and emits `job:skip` (`JobResult.skipped` / `skipReason`); a hook that throws follows the normal retry/error path.
|
|
36
|
+
|
|
37
|
+
## 5.22.1 - 2026-09-25
|
|
38
|
+
|
|
39
|
+
### Changed
|
|
40
|
+
|
|
41
|
+
- Lockstep patch release; package APIs are unchanged.
|
|
42
|
+
|
|
43
|
+
## 5.22.0 - 2026-09-25
|
|
44
|
+
|
|
45
|
+
### Fixed
|
|
46
|
+
|
|
47
|
+
- Cron and time parsing handle absent fields explicitly under strict TypeScript checks.
|
|
48
|
+
|
|
49
|
+
## 5.21.0 - 2026-09-25
|
|
50
|
+
|
|
51
|
+
### Changed
|
|
52
|
+
|
|
53
|
+
- Lockstep release maintenance and dependency refresh.
|
|
54
|
+
## 5.20.0 - 2026-09-24
|
|
55
|
+
|
|
56
|
+
### Added
|
|
57
|
+
|
|
58
|
+
- `job.onOneServer({ lockTtl?, key? })` — run each tick on exactly one server. Every server races for a create-only, TTL-bounded cache claim keyed `scheduler.<key ?? name>.<scheduledTickEpochMs>`. The claim is never released, so exactly one server runs each tick even if another server's timer fires late. Losers skip the tick and emit `job:skip`. Requires a shared cache driver (redis/pg) and a job name or `key`. `@warlock.js/cache` is an optional peer dependency. Default claim TTL is `min(interval, 1h)` with a 60s floor (1h for cron jobs).
|
|
59
|
+
|
|
60
|
+
## 5.19.0 - 2026-09-23
|
|
61
|
+
|
|
62
|
+
### Changed
|
|
63
|
+
|
|
64
|
+
- Refined package skill-discovery descriptions and regenerated the llms projections.
|
|
65
|
+
|
|
66
|
+
## 5.11.0 - 2026-09-14
|
|
67
|
+
|
|
68
|
+
_Released in lockstep with the `@warlock.js/*` family; no package-specific changes in 5.11.0._
|
|
69
|
+
|
|
70
|
+
## 5.10.0 - 2026-09-14
|
|
71
|
+
|
|
72
|
+
_Released in lockstep with the `@warlock.js/*` family; no package-specific changes in 5.10.0._
|
|
73
|
+
|
|
74
|
+
## 5.9.0 - 2026-09-13
|
|
75
|
+
|
|
76
|
+
_Released in lockstep with the `@warlock.js/*` family; no package-specific changes in 5.9.0._
|
|
77
|
+
|
|
78
|
+
## 5.5.0 - 2026-09-07
|
|
79
|
+
|
|
80
|
+
### Fixed
|
|
81
|
+
|
|
82
|
+
- Documentation shipped in this package's `skills/` told users to run `pnpm`-specific commands. `pnpm <binary>` has no npm equivalent, so those instructions failed outright for anyone not using pnpm. Commands are now package-manager neutral.
|
|
83
|
+
|
|
84
|
+
## 5.2.3 - 2026-09-02
|
|
85
|
+
|
|
86
|
+
### Fixed
|
|
87
|
+
|
|
88
|
+
- Released in exact lockstep with Core's Web generator repairs so every family dependency remains installable at 5.2.3.
|
|
89
|
+
|
|
90
|
+
## 5.2.2
|
|
91
|
+
|
|
92
|
+
- Documented: the README, CHANGELOG, and `overview` skill now describe the
|
|
93
|
+
already-shipped `package.json` `"warlock": { "environment": "server" }`
|
|
94
|
+
marker — `@warlock.js/scheduler`'s entire runtime surface is server-only.
|
|
95
|
+
The marker is build-boundary metadata read by `@warlock.js/web`'s Gate A
|
|
96
|
+
(import resolution) and Gate C (emitted-bundle verification); app client
|
|
97
|
+
code must not value-import this package, type-only imports are allowed, and
|
|
98
|
+
server loaders/controllers/modules may import it freely. No source change.
|
|
99
|
+
|
|
100
|
+
## 5.1.0
|
|
101
|
+
|
|
102
|
+
No changes to `@warlock.js/scheduler`. Released in lockstep with the `@warlock.js/web`
|
|
103
|
+
React-execution fix and the `@warlock.js/core` CLI additions — see those packages'
|
|
104
|
+
changelogs.
|
|
105
|
+
|
|
106
|
+
## 5.0.2 - 2026-08-25
|
|
107
|
+
|
|
108
|
+
No changes to `@warlock.js/scheduler`. Released in lockstep with the `@warlock.js/web` SSR
|
|
109
|
+
fix (`ssr.noExternal`) — see that package's changelog.
|
|
110
|
+
|
|
111
|
+
## 5.0.1 - 2026-08-25
|
|
112
|
+
|
|
113
|
+
No changes to `@warlock.js/scheduler`. Released in lockstep with the `create-warlock` vite
|
|
114
|
+
resolution pin and the `@warlock.js/web` peer narrowing — see those packages'
|
|
115
|
+
changelogs.
|
|
116
|
+
|
|
117
|
+
## 5.0.0 - 2026-08-25
|
|
118
|
+
|
|
119
|
+
### Changed
|
|
120
|
+
|
|
121
|
+
- This package is unchanged in 5.0.0; its version moved only because the Warlock family releases in lockstep.
|
|
122
|
+
|
|
123
|
+
## 4.12.0
|
|
124
|
+
|
|
125
|
+
### Changed
|
|
126
|
+
|
|
127
|
+
- Declares its own test runner and pins it to an exact version (`vitest@4.1.10`). The package is its own repository, so a runner resolved from a workspace root it may not be cloned with is a runner it cannot rely on. The pin is exact rather than a range because the version moved underneath the suite mid-development on an unrelated install — a suite whose runner can change without anyone choosing it proves less than it appears to
|
|
128
|
+
|
|
129
|
+
## 4.6.0
|
|
130
|
+
|
|
131
|
+
### Fixed
|
|
132
|
+
|
|
133
|
+
- Warn in development when jobs are registered but `start()` is never called — a one-shot deferred check logs `N job(s) registered but scheduler.start() was never called`, is suppressed once `start()` runs or in production (`NODE_ENV=production`), and is unref'd so it never holds the process open.
|
|
134
|
+
|
|
135
|
+
## 4.1.15
|
|
136
|
+
|
|
137
|
+
- Baseline — per-package changelog tracking starts at this version.
|
package/cjs/index.cjs
CHANGED
|
@@ -993,6 +993,41 @@ function job(name, callback) {
|
|
|
993
993
|
return new Job(name, callback);
|
|
994
994
|
}
|
|
995
995
|
|
|
996
|
+
//#endregion
|
|
997
|
+
//#region ../scheduler/src/process-roles.ts
|
|
998
|
+
/**
|
|
999
|
+
* `WARLOCK_ROLES`, parsed for the scheduler's own use.
|
|
1000
|
+
*
|
|
1001
|
+
* The scheduler has no dependency on `@warlock.js/core` (see package.json),
|
|
1002
|
+
* so it cannot call `Application.hasRole`. Core's `parseRoles` already
|
|
1003
|
+
* validates the raw value at process boot — an unknown role or an explicit
|
|
1004
|
+
* empty list throws there — so this only needs to decide membership, not
|
|
1005
|
+
* re-validate.
|
|
1006
|
+
*/
|
|
1007
|
+
function parsedRoles() {
|
|
1008
|
+
const value = process.env.WARLOCK_ROLES;
|
|
1009
|
+
if (!value) return [];
|
|
1010
|
+
return value.split(",").map((role) => role.trim().toLowerCase()).filter((role) => role.length > 0);
|
|
1011
|
+
}
|
|
1012
|
+
/**
|
|
1013
|
+
* Whether this process serves the `worker` role.
|
|
1014
|
+
*
|
|
1015
|
+
* `true` when `WARLOCK_ROLES` is unset, matching core's default of "every
|
|
1016
|
+
* role is on" for plain `start`, `dev`, and tests.
|
|
1017
|
+
*/
|
|
1018
|
+
function hasWorkerRole() {
|
|
1019
|
+
const roles = parsedRoles();
|
|
1020
|
+
return roles.length === 0 || roles.includes("worker");
|
|
1021
|
+
}
|
|
1022
|
+
/**
|
|
1023
|
+
* The roles this process serves, formatted for a log line — `"all"` when
|
|
1024
|
+
* `WARLOCK_ROLES` is unset.
|
|
1025
|
+
*/
|
|
1026
|
+
function rolesLabel() {
|
|
1027
|
+
const roles = parsedRoles();
|
|
1028
|
+
return roles.length === 0 ? "all" : roles.join(",");
|
|
1029
|
+
}
|
|
1030
|
+
|
|
996
1031
|
//#endregion
|
|
997
1032
|
//#region ../scheduler/src/scheduler.ts
|
|
998
1033
|
/**
|
|
@@ -1161,9 +1196,18 @@ var Scheduler = class extends node_events.EventEmitter {
|
|
|
1161
1196
|
/**
|
|
1162
1197
|
* Start the scheduler
|
|
1163
1198
|
*
|
|
1199
|
+
* A no-op, logging one info line, on a process that does not serve the
|
|
1200
|
+
* `worker` role (`WARLOCK_ROLES`) — so an app that calls this in `main.ts`
|
|
1201
|
+
* doesn't run its jobs on every `web`/`api` node. With no `--role` passed,
|
|
1202
|
+
* every role is on and this behaves exactly as before.
|
|
1203
|
+
*
|
|
1164
1204
|
* @throws Error if scheduler is already running
|
|
1165
1205
|
*/
|
|
1166
1206
|
start() {
|
|
1207
|
+
if (!hasWorkerRole()) {
|
|
1208
|
+
console.info(`scheduler: not started (role: ${rolesLabel()})`);
|
|
1209
|
+
return;
|
|
1210
|
+
}
|
|
1167
1211
|
if (this.isRunning) throw new Error("Scheduler is already running.");
|
|
1168
1212
|
if (this._jobs.length === 0) throw new Error("Cannot start scheduler with no jobs.");
|
|
1169
1213
|
this._hasStarted = true;
|
|
@@ -1203,12 +1247,14 @@ var Scheduler = class extends node_events.EventEmitter {
|
|
|
1203
1247
|
* Arm the one-shot "registered but never started" development warning.
|
|
1204
1248
|
*
|
|
1205
1249
|
* Called whenever a job is registered. Does nothing in production
|
|
1206
|
-
* (`NODE_ENV === "production"`), once `start()` has been called,
|
|
1207
|
-
* check is already armed
|
|
1250
|
+
* (`NODE_ENV === "production"`), once `start()` has been called, when a
|
|
1251
|
+
* check is already armed, or when this process doesn't serve the `worker`
|
|
1252
|
+
* role — `start()` is never expected to be called there, so the warning
|
|
1253
|
+
* would only be noise. The deferred check is unref'd so it can never keep
|
|
1208
1254
|
* the event loop (and the process) alive on its own.
|
|
1209
1255
|
*/
|
|
1210
1256
|
_armStartWarning() {
|
|
1211
|
-
if (process.env.NODE_ENV === "production") return;
|
|
1257
|
+
if (process.env.NODE_ENV === "production" || !hasWorkerRole()) return;
|
|
1212
1258
|
if (this._hasStarted || this._startWarningTimer !== null) return;
|
|
1213
1259
|
const timer = setTimeout(() => {
|
|
1214
1260
|
this._startWarningTimer = null;
|