@warlock.js/queue 5.13.0 → 5.15.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 +27 -0
- package/README.md +43 -7
- package/cjs/index.cjs +525 -29
- package/cjs/index.cjs.map +1 -1
- package/esm/dashboard-boot.d.mts +20 -0
- package/esm/dashboard-boot.d.mts.map +1 -0
- package/esm/dashboard-boot.mjs +38 -0
- package/esm/dashboard-boot.mjs.map +1 -0
- package/esm/dashboard-guard-plugin.mjs +28 -0
- package/esm/dashboard-guard-plugin.mjs.map +1 -0
- package/esm/dashboard-middleware-adapter.mjs +39 -0
- package/esm/dashboard-middleware-adapter.mjs.map +1 -0
- package/esm/dashboard.d.mts +8 -0
- package/esm/dashboard.d.mts.map +1 -1
- package/esm/dashboard.mjs +3 -1
- package/esm/dashboard.mjs.map +1 -1
- package/esm/define-job.mjs +13 -6
- package/esm/define-job.mjs.map +1 -1
- package/esm/index.d.mts +4 -2
- package/esm/index.mjs +3 -1
- package/esm/queue-connector.d.mts.map +1 -1
- package/esm/queue-connector.mjs +17 -1
- package/esm/queue-connector.mjs.map +1 -1
- package/esm/queue-dashboard-unguarded.error.d.mts +13 -0
- package/esm/queue-dashboard-unguarded.error.d.mts.map +1 -0
- package/esm/queue-dashboard-unguarded.error.mjs +17 -0
- package/esm/queue-dashboard-unguarded.error.mjs.map +1 -0
- package/esm/types.d.mts +19 -2
- package/esm/types.d.mts.map +1 -1
- package/llms-full.txt +45 -9
- package/llms.txt +2 -2
- package/package.json +3 -17
- package/skills/configure-queue/SKILL.md +4 -0
- package/skills/manage-failed-jobs/SKILL.md +33 -4
- package/skills/overview/SKILL.md +1 -1
- package/skills/queue-notifications/SKILL.md +6 -4
- package/cjs/define-job-DideGKQK.cjs +0 -468
- package/cjs/define-job-DideGKQK.cjs.map +0 -1
- package/cjs/notifications/index.cjs +0 -68
- package/cjs/notifications/index.cjs.map +0 -1
- package/esm/notifications/index.d.mts +0 -2
- package/esm/notifications/index.mjs +0 -3
- package/esm/notifications/queue-notification-dispatcher.d.mts +0 -34
- package/esm/notifications/queue-notification-dispatcher.d.mts.map +0 -1
- package/esm/notifications/queue-notification-dispatcher.mjs +0 -67
- package/esm/notifications/queue-notification-dispatcher.mjs.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"queue-dashboard-unguarded.error.mjs","names":[],"sources":["../../../../../../queue/src/queue-dashboard-unguarded.error.ts"],"sourcesContent":["/**\n * Thrown at boot when `queue.dashboard.enabled` is `true` in production with\n * no guard middleware. The dashboard can retry and delete jobs; mounting it\n * on the open internet without a guard is a production incident waiting to\n * happen, so this fails the boot instead of shipping the hole.\n */\nexport class QueueDashboardUnguardedError extends Error {\n public constructor() {\n super(\n \"queue.dashboard.enabled is true in production with no middleware. The dashboard can \" +\n \"retry and delete jobs, so it must be guarded before it is exposed.\\n\\n\" +\n \"Add a guard middleware:\\n\\n\" +\n \" import { middleware } from \\\"@warlock.js/core\\\";\\n\" +\n \" import { authMiddleware } from \\\"@warlock.js/auth\\\";\\n\\n\" +\n \" const queueConfig: QueueConfig = {\\n\" +\n \" // ...\\n\" +\n \" dashboard: {\\n\" +\n \" enabled: true,\\n\" +\n \" middleware: [authMiddleware(\\\"admin\\\")],\\n\" +\n \" },\\n\" +\n \" };\\n\",\n );\n this.name = \"QueueDashboardUnguardedError\";\n }\n}\n"],"mappings":";;;;;;;AAMA,IAAa,+BAAb,cAAkD,MAAM;CACtD,AAAO,cAAc;EACnB,MACE,6bAYF;EACA,KAAK,OAAO;CACd;AACF"}
|
package/esm/types.d.mts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { ConnectionOptions } from "bullmq";
|
|
2
|
+
import { Middleware } from "@warlock.js/core";
|
|
2
3
|
|
|
3
4
|
//#region ../queue/src/types.d.ts
|
|
4
5
|
/** Units accepted in a {@link Duration} string. */
|
|
@@ -47,6 +48,21 @@ type QueueWorkersConfig = {
|
|
|
47
48
|
*/
|
|
48
49
|
shutdownTimeout?: number;
|
|
49
50
|
};
|
|
51
|
+
/**
|
|
52
|
+
* The bull-board dashboard, mounted automatically by `queueConnector()` when
|
|
53
|
+
* `enabled` is `true`. Equivalent to calling `queueDashboard()` yourself at
|
|
54
|
+
* boot, driven by config instead — see `warlock add bull-board`.
|
|
55
|
+
*/
|
|
56
|
+
type QueueDashboardConfig = {
|
|
57
|
+
/** Mount the dashboard at boot. Default `false`. */enabled?: boolean; /** URL path the dashboard is mounted on. Default `"/admin/queues"`. */
|
|
58
|
+
path?: string;
|
|
59
|
+
/**
|
|
60
|
+
* Run before every dashboard route — this is how the dashboard is guarded.
|
|
61
|
+
* The dashboard can retry and delete jobs, so `NODE_ENV === "production"`
|
|
62
|
+
* with an empty list throws `QueueDashboardUnguardedError` at boot.
|
|
63
|
+
*/
|
|
64
|
+
middleware?: Middleware[];
|
|
65
|
+
};
|
|
50
66
|
/**
|
|
51
67
|
* The `queue` configuration key — `src/config/queue.ts`.
|
|
52
68
|
*/
|
|
@@ -59,7 +75,8 @@ type QueueConfig = {
|
|
|
59
75
|
prefix?: string; /** Queue name used when a job does not name one. Default `"default"`. */
|
|
60
76
|
defaultQueue?: string; /** Defaults merged under every job's own options. */
|
|
61
77
|
defaultJobOptions?: JobOptions; /** In-process workers. */
|
|
62
|
-
workers?: QueueWorkersConfig;
|
|
78
|
+
workers?: QueueWorkersConfig; /** The bull-board job dashboard. */
|
|
79
|
+
dashboard?: QueueDashboardConfig;
|
|
63
80
|
};
|
|
64
81
|
/** A progress value: a number (e.g. a percentage) or a JSON object. */
|
|
65
82
|
type JobProgress = number | Record<string, unknown>;
|
|
@@ -145,5 +162,5 @@ type QueueJob<TPayload, TResult = unknown> = {
|
|
|
145
162
|
find(id: string): Promise<JobSnapshot<TPayload, TResult> | undefined>;
|
|
146
163
|
};
|
|
147
164
|
//#endregion
|
|
148
|
-
export { DispatchOptions, DispatchedJob, Duration, DurationUnit, FailedJob, JobBackoff, JobContext, JobDefinition, JobOptions, JobProgress, JobRetention, JobSnapshot, JobState, QueueConfig, QueueJob, QueueWorkersConfig };
|
|
165
|
+
export { DispatchOptions, DispatchedJob, Duration, DurationUnit, FailedJob, JobBackoff, JobContext, JobDefinition, JobOptions, JobProgress, JobRetention, JobSnapshot, JobState, QueueConfig, QueueDashboardConfig, QueueJob, QueueWorkersConfig };
|
|
149
166
|
//# sourceMappingURL=types.d.mts.map
|
package/esm/types.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.mts","names":[],"sources":["../../../../../../queue/src/types.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"types.d.mts","names":[],"sources":["../../../../../../queue/src/types.ts"],"mappings":";;;;;KAIY,YAAA;AAAZ;;;;AAAA,KAMY,QAAA,wBAAgC,YAAY;AAAxD;;;;AAAA,KAMY,UAAA;EAAA,uFAIN,IAAA;EAEA,KAAK;AAAA;AAOX;;;;AAAA,KAAY,YAAA;AAMZ;;;;AAAA,KAAY,UAAA;EAQK,kEANf,QAAA,WAM2B;EAJ3B,OAAA,GAAU,UAAA,EAAV;EAEA,gBAAA,GAAmB,YAAA,EAAnB;EAEA,YAAA,GAAe,YAAA;AAAA;;;AAAY;KAMjB,kBAAA;EAAkB;;;;EAK5B,OAAA,YAOA;EALA,WAAA;EAKe;AAQjB;;;EARE,eAAA;AAAA;;;;;AAkBuB;KAVb,oBAAA;EAgBW,oDAdrB,OAAA,YAmBY;EAjBZ,IAAA;EAyBU;;;;;EAnBV,UAAA,GAAa,UAAU;AAAA;;;;KAMb,WAAA;EAaA;;;;EARV,UAAA,EAAY,iBAAA,EAcF;EAZV,MAAA;EAEA,YAAA,WAUuC;EARvC,iBAAA,GAAoB,UAAA,EAaA;EAXpB,OAAA,GAAU,kBAAA,EAuBM;EArBhB,SAAA,GAAY,oBAAA;AAAA;;KAIF,WAAA,YAAuB,MAAM;;;;KAK7B,UAAA;EAUV,kBARA,EAAA,UAUgB;EARhB,IAAA,UAQ8B;EAN9B,KAAA,UAQI;EANJ,OAAA,UAM0B;EAJ1B,WAAA,UAUU;EARV,QAAA,CAAS,KAAA,EAAO,WAAA,GAAc,OAAA,QAQP;EANvB,GAAA,CAAI,IAAA,WAAe,OAAA;AAAA;;;;KAMT,aAAA,sBAAmC,UAAA;EAM6B,+CAJ1E,IAAA,UAFwB;EAIxB,KAAA,WAJ6C;EAM7C,MAAA,CAAO,OAAA,EAAS,QAAA,EAAU,OAAA,EAAS,UAAA,GAAa,OAAA,CAAQ,OAAA,IAAW,OAAA;AAAA;;;;KAMzD,eAAA;EANgB,6CAQ1B,KAAA,GAAQ,QAAA;EARgD;;;AAAkB;EAa1E,QAAA;EAPyB;;;;EAYzB,KAAA,WALA;EAOA,QAAA;EAEA,OAAA,GAAU,UAAU;AAAA;;KAIV,aAAA;EACV,EAAA;EACA,IAAA;EACA,KAAA;AAAA;;KAIU,QAAA;;KAWA,WAAA;EACV,EAAA;EACA,IAAA;EACA,KAAA;EACA,KAAA,EAAO,QAAA;EACP,OAAA,EAAS,QAAA;EACT,QAAA,EAAU,WAAA;EACV,YAAA;EACA,MAAA,GAAS,OAAA;EACT,YAAA;EACA,SAAA,EAAW,IAAA;EACX,UAAA,GAAa,IAAA;AAAA;;KAIH,SAAA;EACV,EAAA;EACA,IAAA;EACA,KAAA;EACA,OAAA,EAAS,QAAA;EACT,YAAA;EACA,YAAA;EACA,UAAA;EACA,QAAA,GAAW,IAAA,EAnBX;EAqBA,KAAA,IAAS,OAAA;AAAA;;;;KAMC,QAAA;EAAA,SACD,IAAA;EAAA,SACA,KAAA,UAxBT;EA0BA,QAAA,CAAS,OAAA,EAAS,QAAA,EAAU,OAAA,GAAU,eAAA,GAAkB,OAAA,CAAQ,aAAA,GAzBrD;EA2BX,IAAA,CAAK,EAAA,WAAa,OAAA,CAAQ,WAAA,CAAY,QAAA,EAAU,OAAA;AAAA"}
|
package/llms-full.txt
CHANGED
|
@@ -62,6 +62,10 @@ process.on("SIGTERM", () => closeQueue());
|
|
|
62
62
|
|
|
63
63
|
Every process must use the same `prefix`, or they will not see each other's jobs.
|
|
64
64
|
|
|
65
|
+
## Dashboard
|
|
66
|
+
|
|
67
|
+
`QueueConfig` also takes a `dashboard: { enabled, path, middleware }` block — see [`manage-failed-jobs`](../manage-failed-jobs/SKILL.md#dashboard-optional) for the `warlock add bull-board` setup and the production guard (`QueueDashboardUnguardedError`).
|
|
68
|
+
|
|
65
69
|
|
|
66
70
|
## define-jobs `@warlock.js/queue/define-jobs/SKILL.md`
|
|
67
71
|
|
|
@@ -122,7 +126,7 @@ const job = await sendInvoice.find(id);
|
|
|
122
126
|
|
|
123
127
|
---
|
|
124
128
|
name: manage-failed-jobs
|
|
125
|
-
description: 'Inspect and retry failed `@warlock.js/queue` jobs: `failedJobs({ queue, start, end })` returns `FailedJob[]` (`id`, `name`, `payload`, `attemptsMade`, `failedReason`, `stacktrace`, `failedAt`, `retry()`), `retryFailedJob(id, { queue })` (throws `FailedJobNotFoundError`), and the
|
|
129
|
+
description: 'Inspect and retry failed `@warlock.js/queue` jobs: `failedJobs({ queue, start, end })` returns `FailedJob[]` (`id`, `name`, `payload`, `attemptsMade`, `failedReason`, `stacktrace`, `failedAt`, `retry()`), `retryFailedJob(id, { queue })` (throws `FailedJobNotFoundError`), and the bull-board UI — `warlock add bull-board` (requires: ["queue"], so it installs queue first when missing) writes a `dashboard: { enabled, path, middleware }` block to `src/config/queue.ts`; a guard middleware is required in production or boot throws `QueueDashboardUnguardedError`. Manual `queueDashboard(server, { basePath, queues, middleware })` also available — needs `@bull-board/api` + `@bull-board/fastify`, loaded only on call, missing ones throw `QueueDashboardDependencyError`. Triggers: `failedJobs`, `retryFailedJob`, `queueDashboard`, `bull-board`, `dashboard.enabled`, `QueueDashboardUnguardedError`; "list failed jobs", "retry a failed job", "queue dashboard", "job admin UI". Skip: defining retries — `@warlock.js/queue/define-jobs/SKILL.md`.'
|
|
126
130
|
---
|
|
127
131
|
|
|
128
132
|
# Failed jobs
|
|
@@ -145,19 +149,48 @@ await retryFailedJob("invoice:43"); // by id; throws FailedJobNotFoundError if n
|
|
|
145
149
|
## Dashboard (optional)
|
|
146
150
|
|
|
147
151
|
```sh
|
|
148
|
-
|
|
152
|
+
warlock add bull-board
|
|
149
153
|
```
|
|
150
154
|
|
|
155
|
+
This installs `@bull-board/api` + `@bull-board/fastify` and writes a `dashboard` block to `src/config/queue.ts`. It `requires: ["queue"]`, so it adds the `queue` feature first automatically when it isn't installed yet — no need to run `warlock add queue` yourself first:
|
|
156
|
+
|
|
157
|
+
```ts title="src/config/queue.ts"
|
|
158
|
+
import type { QueueConfig } from "@warlock.js/queue";
|
|
159
|
+
import { middleware } from "@warlock.js/core";
|
|
160
|
+
import { authMiddleware } from "@warlock.js/auth";
|
|
161
|
+
|
|
162
|
+
const queueConfig: QueueConfig = {
|
|
163
|
+
// ...
|
|
164
|
+
dashboard: {
|
|
165
|
+
enabled: true,
|
|
166
|
+
path: "/admin/queues", // default
|
|
167
|
+
middleware: [authMiddleware("admin")], // guards every dashboard route
|
|
168
|
+
},
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
export default queueConfig;
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
- The dashboard can retry and delete jobs, so it must be guarded. In production, an empty `middleware` list throws `QueueDashboardUnguardedError` at boot instead of mounting exposed. Outside production it logs a warning and mounts anyway.
|
|
175
|
+
- `queueConnector()` mounts the dashboard at boot from this config — no extra wiring needed.
|
|
176
|
+
|
|
177
|
+
### Advanced: manual `queueDashboard()`
|
|
178
|
+
|
|
179
|
+
For mounting outside the config-driven path (a custom server, a non-standard boot sequence), call `queueDashboard` yourself:
|
|
180
|
+
|
|
151
181
|
```ts
|
|
152
182
|
import { getHttpServer } from "@warlock.js/core";
|
|
153
183
|
import { queueDashboard } from "@warlock.js/queue";
|
|
154
184
|
|
|
155
|
-
await queueDashboard(getHttpServer(), {
|
|
185
|
+
await queueDashboard(getHttpServer(), {
|
|
186
|
+
basePath: "/admin/queues",
|
|
187
|
+
middleware: [authMiddleware("admin")],
|
|
188
|
+
});
|
|
156
189
|
```
|
|
157
190
|
|
|
158
191
|
- Call it before the HTTP server starts listening.
|
|
159
192
|
- Shows every queue that has a job, plus the default queue, unless you pass `queues`.
|
|
160
|
-
- It has no authentication of its own
|
|
193
|
+
- It has no authentication of its own — pass `middleware` yourself; this path does not enforce the production guard that the `dashboard` config does.
|
|
161
194
|
|
|
162
195
|
|
|
163
196
|
## overview `@warlock.js/queue/overview/SKILL.md`
|
|
@@ -187,30 +220,31 @@ Durable background jobs. Jobs are stored in **Redis** (required), retried on fai
|
|
|
187
220
|
- [`configure-queue`](@warlock.js/queue/configure-queue/SKILL.md) — `src/config/queue.ts`, `queueConnector()`, workers on/off, shutdown.
|
|
188
221
|
- [`define-jobs`](@warlock.js/queue/define-jobs/SKILL.md) — `defineJob`, `dispatch` options, retries, progress, `find`.
|
|
189
222
|
- [`manage-failed-jobs`](@warlock.js/queue/manage-failed-jobs/SKILL.md) — `failedJobs`, `retryFailedJob`, the bull-board dashboard.
|
|
190
|
-
- [`queue-notifications`](@warlock.js/queue/queue-notifications/SKILL.md) — `
|
|
223
|
+
- [`queue-notifications`](@warlock.js/queue/queue-notifications/SKILL.md) — `bullmqQueue()` for notifications `.queue()`.
|
|
191
224
|
|
|
192
225
|
|
|
193
226
|
## queue-notifications `@warlock.js/queue/queue-notifications/SKILL.md`
|
|
194
227
|
|
|
195
228
|
---
|
|
196
229
|
name: queue-notifications
|
|
197
|
-
description: 'Send `@warlock.js/notifications` `.queue()` deliveries through BullMQ with `
|
|
230
|
+
description: 'Send `@warlock.js/notifications` `.queue()` deliveries through BullMQ with `bullmqQueue({ queue?, attempts?, backoff? })` from `@warlock.js/notifications` — put it in the `queue` slot of `src/config/notifications.ts`; the queue workers deliver. Honours `SendOptions.delay` (number = seconds, or "10m"), retries a failing `channel.send`, and fails at once for a channel missing from the worker config. Triggers: `bullmqQueue`, `NotificationConfig.queue`, `QueuePackageNotInstalledError`; "queue notifications with BullMQ", "retry notification delivery", "delayed notification". Skip: the herald backend — `@warlock.js/notifications/queue-notifications/SKILL.md`.'
|
|
198
231
|
---
|
|
199
232
|
|
|
200
233
|
# Queue notifications with BullMQ
|
|
201
234
|
|
|
202
235
|
```ts title="src/config/notifications.ts"
|
|
203
|
-
import { type NotificationConfig, mailChannel } from "@warlock.js/notifications";
|
|
204
|
-
import { queueNotificationDispatcher } from "@warlock.js/queue/notifications";
|
|
236
|
+
import { type NotificationConfig, bullmqQueue, mailChannel } from "@warlock.js/notifications";
|
|
205
237
|
|
|
206
238
|
const config: NotificationConfig = {
|
|
207
239
|
channels: { mail: mailChannel() },
|
|
208
|
-
queue:
|
|
240
|
+
queue: bullmqQueue({ attempts: 3, backoff: { type: "exponential", delay: 5000 } }),
|
|
209
241
|
};
|
|
210
242
|
|
|
211
243
|
export default config;
|
|
212
244
|
```
|
|
213
245
|
|
|
246
|
+
`bullmqQueue` ships inside `@warlock.js/notifications` itself and lazy-loads `@warlock.js/queue` (an OPTIONAL peer) the first time `.queue()` runs — install it with `warlock add queue` if it isn't there yet, otherwise the first `.queue()` throws `QueuePackageNotInstalledError`.
|
|
247
|
+
|
|
214
248
|
Also configure the queue itself (`configure-queue`). No separate notifications worker is needed: the delivery is an ordinary job, run by the queue workers.
|
|
215
249
|
|
|
216
250
|
```ts
|
|
@@ -226,4 +260,6 @@ await orderShipped.queue(user, { order }, { delay: "10m" }); // delivered in 10
|
|
|
226
260
|
- Channel not configured in the worker → fails at once, no retries.
|
|
227
261
|
- Deliveries run under the job name `warlock.notifications.deliver`.
|
|
228
262
|
|
|
263
|
+
> **Deprecated:** `queueNotificationDispatcher` from `@warlock.js/queue/notifications` still works this release (it logs a one-time deprecation warning) and is removed next release. Migrate to `bullmqQueue` above — same option names (`queue`, `attempts`, `backoff`).
|
|
264
|
+
|
|
229
265
|
|
package/llms.txt
CHANGED
|
@@ -8,6 +8,6 @@
|
|
|
8
8
|
|
|
9
9
|
- [configure-queue](@warlock.js/queue/configure-queue/SKILL.md): Configure `@warlock.js/queue`: the declarative `src/config/queue.ts` (`QueueConfig` — `connection`, `prefix`, `defaultQueue`, `defaultJobOptions`, `workers: { enabled, concurrency, shutdownTimeout }`), registering `queueConnector()` in `warlock.config.ts > connectors`, running a dispatch-only process, and graceful shutdown. Programmatic `setQueueConfig` / `startWorkers` / `closeQueue` for scripts and tests. Triggers: `QueueConfig`, `queueConnector`, `setQueueConfig`, `startWorkers`, `closeQueue`, `workers.enabled`, `shutdownTimeout`; "configure the queue", "connect BullMQ to Redis", "disable workers in the web process", "graceful shutdown of jobs". Skip: writing jobs — `@warlock.js/queue/define-jobs/SKILL.md`.
|
|
10
10
|
- [define-jobs](@warlock.js/queue/define-jobs/SKILL.md): Define and dispatch background jobs with `@warlock.js/queue`: `defineJob({ name, queue?, attempts?, backoff?, removeOnComplete?, removeOnFail?, handle(payload, ctx) })` returns a typed job; `job.dispatch(payload, { delay, priority, jobId, attempts, backoff })`; the handler context (`id`, `attempt`, `maxAttempts`, `progress()`, `log()`); reading a job with `job.find(id)`. Triggers: `defineJob`, `.dispatch(`, `ctx.progress`, `JobContext`, `DispatchOptions`, `backoff`, `attempts`, `priority`, `jobId`; "run this in the background", "retry with backoff", "delay a job", "job progress", "idempotent dispatch". Skip: config and workers — `@warlock.js/queue/configure-queue/SKILL.md`; failed jobs — `@warlock.js/queue/manage-failed-jobs/SKILL.md`.
|
|
11
|
-
- [manage-failed-jobs](@warlock.js/queue/manage-failed-jobs/SKILL.md): Inspect and retry failed `@warlock.js/queue` jobs: `failedJobs({ queue, start, end })` returns `FailedJob[]` (`id`, `name`, `payload`, `attemptsMade`, `failedReason`, `stacktrace`, `failedAt`, `retry()`), `retryFailedJob(id, { queue })` (throws `FailedJobNotFoundError`), and the
|
|
11
|
+
- [manage-failed-jobs](@warlock.js/queue/manage-failed-jobs/SKILL.md): Inspect and retry failed `@warlock.js/queue` jobs: `failedJobs({ queue, start, end })` returns `FailedJob[]` (`id`, `name`, `payload`, `attemptsMade`, `failedReason`, `stacktrace`, `failedAt`, `retry()`), `retryFailedJob(id, { queue })` (throws `FailedJobNotFoundError`), and the bull-board UI — `warlock add bull-board` (requires: ["queue"], so it installs queue first when missing) writes a `dashboard: { enabled, path, middleware }` block to `src/config/queue.ts`; a guard middleware is required in production or boot throws `QueueDashboardUnguardedError`. Manual `queueDashboard(server, { basePath, queues, middleware })` also available — needs `@bull-board/api` + `@bull-board/fastify`, loaded only on call, missing ones throw `QueueDashboardDependencyError`. Triggers: `failedJobs`, `retryFailedJob`, `queueDashboard`, `bull-board`, `dashboard.enabled`, `QueueDashboardUnguardedError`; "list failed jobs", "retry a failed job", "queue dashboard", "job admin UI". Skip: defining retries — `@warlock.js/queue/define-jobs/SKILL.md`.
|
|
12
12
|
- [overview](@warlock.js/queue/overview/SKILL.md): Front door for `@warlock.js/queue` — durable background jobs for Warlock apps on BullMQ + Redis (Redis is required): `defineJob` + `.dispatch()`, retries/backoff, delay, priority, progress, failed-job listing/retry, in-process workers started by `queueConnector()` with graceful shutdown, a BullMQ backend for notifications `.queue()`, and an optional bull-board dashboard. TRIGGER when: importing from `@warlock.js/queue`; "background job", "job queue", "run this later", "retry failed jobs", "BullMQ in Warlock", "worker process". Skip: in-memory batching inside one process — that is core's `Queue` class (`@warlock.js/core`); cron-style schedules — `@warlock.js/scheduler/overview/SKILL.md`; a known task — load `configure-queue`, `define-jobs`, `manage-failed-jobs` or `queue-notifications`.
|
|
13
|
-
- [queue-notifications](@warlock.js/queue/queue-notifications/SKILL.md): Send `@warlock.js/notifications` `.queue()` deliveries through BullMQ with `
|
|
13
|
+
- [queue-notifications](@warlock.js/queue/queue-notifications/SKILL.md): Send `@warlock.js/notifications` `.queue()` deliveries through BullMQ with `bullmqQueue({ queue?, attempts?, backoff? })` from `@warlock.js/notifications` — put it in the `queue` slot of `src/config/notifications.ts`; the queue workers deliver. Honours `SendOptions.delay` (number = seconds, or "10m"), retries a failing `channel.send`, and fails at once for a channel missing from the worker config. Triggers: `bullmqQueue`, `NotificationConfig.queue`, `QueuePackageNotInstalledError`; "queue notifications with BullMQ", "retry notification delivery", "delayed notification". Skip: the herald backend — `@warlock.js/notifications/queue-notifications/SKILL.md`.
|
package/package.json
CHANGED
|
@@ -11,9 +11,8 @@
|
|
|
11
11
|
"peerDependencies": {
|
|
12
12
|
"@bull-board/api": "^9.0.0",
|
|
13
13
|
"@bull-board/fastify": "^9.0.0",
|
|
14
|
-
"@warlock.js/core": "5.
|
|
15
|
-
"@warlock.js/logger": "5.
|
|
16
|
-
"@warlock.js/notifications": "5.13.0"
|
|
14
|
+
"@warlock.js/core": "5.15.0",
|
|
15
|
+
"@warlock.js/logger": "5.15.0"
|
|
17
16
|
},
|
|
18
17
|
"peerDependenciesMeta": {
|
|
19
18
|
"@bull-board/api": {
|
|
@@ -21,9 +20,6 @@
|
|
|
21
20
|
},
|
|
22
21
|
"@bull-board/fastify": {
|
|
23
22
|
"optional": true
|
|
24
|
-
},
|
|
25
|
-
"@warlock.js/notifications": {
|
|
26
|
-
"optional": true
|
|
27
23
|
}
|
|
28
24
|
},
|
|
29
25
|
"repository": {
|
|
@@ -41,7 +37,7 @@
|
|
|
41
37
|
],
|
|
42
38
|
"author": "hassanzohdy",
|
|
43
39
|
"license": "MIT",
|
|
44
|
-
"version": "5.
|
|
40
|
+
"version": "5.15.0",
|
|
45
41
|
"main": "./cjs/index.cjs",
|
|
46
42
|
"module": "./esm/index.mjs",
|
|
47
43
|
"types": "./esm/index.d.mts",
|
|
@@ -55,16 +51,6 @@
|
|
|
55
51
|
"types": "./esm/index.d.mts",
|
|
56
52
|
"default": "./cjs/index.cjs"
|
|
57
53
|
}
|
|
58
|
-
},
|
|
59
|
-
"./notifications": {
|
|
60
|
-
"import": {
|
|
61
|
-
"types": "./esm/notifications/index.d.mts",
|
|
62
|
-
"default": "./esm/notifications/index.mjs"
|
|
63
|
-
},
|
|
64
|
-
"require": {
|
|
65
|
-
"types": "./esm/notifications/index.d.mts",
|
|
66
|
-
"default": "./cjs/notifications/index.cjs"
|
|
67
|
-
}
|
|
68
54
|
}
|
|
69
55
|
}
|
|
70
56
|
}
|
|
@@ -53,3 +53,7 @@ process.on("SIGTERM", () => closeQueue());
|
|
|
53
53
|
```
|
|
54
54
|
|
|
55
55
|
Every process must use the same `prefix`, or they will not see each other's jobs.
|
|
56
|
+
|
|
57
|
+
## Dashboard
|
|
58
|
+
|
|
59
|
+
`QueueConfig` also takes a `dashboard: { enabled, path, middleware }` block — see [`manage-failed-jobs`](../manage-failed-jobs/SKILL.md#dashboard-optional) for the `warlock add bull-board` setup and the production guard (`QueueDashboardUnguardedError`).
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: manage-failed-jobs
|
|
3
|
-
description: 'Inspect and retry failed `@warlock.js/queue` jobs: `failedJobs({ queue, start, end })` returns `FailedJob[]` (`id`, `name`, `payload`, `attemptsMade`, `failedReason`, `stacktrace`, `failedAt`, `retry()`), `retryFailedJob(id, { queue })` (throws `FailedJobNotFoundError`), and the
|
|
3
|
+
description: 'Inspect and retry failed `@warlock.js/queue` jobs: `failedJobs({ queue, start, end })` returns `FailedJob[]` (`id`, `name`, `payload`, `attemptsMade`, `failedReason`, `stacktrace`, `failedAt`, `retry()`), `retryFailedJob(id, { queue })` (throws `FailedJobNotFoundError`), and the bull-board UI — `warlock add bull-board` (requires: ["queue"], so it installs queue first when missing) writes a `dashboard: { enabled, path, middleware }` block to `src/config/queue.ts`; a guard middleware is required in production or boot throws `QueueDashboardUnguardedError`. Manual `queueDashboard(server, { basePath, queues, middleware })` also available — needs `@bull-board/api` + `@bull-board/fastify`, loaded only on call, missing ones throw `QueueDashboardDependencyError`. Triggers: `failedJobs`, `retryFailedJob`, `queueDashboard`, `bull-board`, `dashboard.enabled`, `QueueDashboardUnguardedError`; "list failed jobs", "retry a failed job", "queue dashboard", "job admin UI". Skip: defining retries — `@warlock.js/queue/define-jobs/SKILL.md`.'
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Failed jobs
|
|
@@ -23,16 +23,45 @@ await retryFailedJob("invoice:43"); // by id; throws FailedJobNotFoundError if n
|
|
|
23
23
|
## Dashboard (optional)
|
|
24
24
|
|
|
25
25
|
```sh
|
|
26
|
-
|
|
26
|
+
warlock add bull-board
|
|
27
27
|
```
|
|
28
28
|
|
|
29
|
+
This installs `@bull-board/api` + `@bull-board/fastify` and writes a `dashboard` block to `src/config/queue.ts`. It `requires: ["queue"]`, so it adds the `queue` feature first automatically when it isn't installed yet — no need to run `warlock add queue` yourself first:
|
|
30
|
+
|
|
31
|
+
```ts title="src/config/queue.ts"
|
|
32
|
+
import type { QueueConfig } from "@warlock.js/queue";
|
|
33
|
+
import { middleware } from "@warlock.js/core";
|
|
34
|
+
import { authMiddleware } from "@warlock.js/auth";
|
|
35
|
+
|
|
36
|
+
const queueConfig: QueueConfig = {
|
|
37
|
+
// ...
|
|
38
|
+
dashboard: {
|
|
39
|
+
enabled: true,
|
|
40
|
+
path: "/admin/queues", // default
|
|
41
|
+
middleware: [authMiddleware("admin")], // guards every dashboard route
|
|
42
|
+
},
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
export default queueConfig;
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
- The dashboard can retry and delete jobs, so it must be guarded. In production, an empty `middleware` list throws `QueueDashboardUnguardedError` at boot instead of mounting exposed. Outside production it logs a warning and mounts anyway.
|
|
49
|
+
- `queueConnector()` mounts the dashboard at boot from this config — no extra wiring needed.
|
|
50
|
+
|
|
51
|
+
### Advanced: manual `queueDashboard()`
|
|
52
|
+
|
|
53
|
+
For mounting outside the config-driven path (a custom server, a non-standard boot sequence), call `queueDashboard` yourself:
|
|
54
|
+
|
|
29
55
|
```ts
|
|
30
56
|
import { getHttpServer } from "@warlock.js/core";
|
|
31
57
|
import { queueDashboard } from "@warlock.js/queue";
|
|
32
58
|
|
|
33
|
-
await queueDashboard(getHttpServer(), {
|
|
59
|
+
await queueDashboard(getHttpServer(), {
|
|
60
|
+
basePath: "/admin/queues",
|
|
61
|
+
middleware: [authMiddleware("admin")],
|
|
62
|
+
});
|
|
34
63
|
```
|
|
35
64
|
|
|
36
65
|
- Call it before the HTTP server starts listening.
|
|
37
66
|
- Shows every queue that has a job, plus the default queue, unless you pass `queues`.
|
|
38
|
-
- It has no authentication of its own
|
|
67
|
+
- It has no authentication of its own — pass `middleware` yourself; this path does not enforce the production guard that the `dashboard` config does.
|
package/skills/overview/SKILL.md
CHANGED
|
@@ -23,4 +23,4 @@ Durable background jobs. Jobs are stored in **Redis** (required), retried on fai
|
|
|
23
23
|
- [`configure-queue`](@warlock.js/queue/configure-queue/SKILL.md) — `src/config/queue.ts`, `queueConnector()`, workers on/off, shutdown.
|
|
24
24
|
- [`define-jobs`](@warlock.js/queue/define-jobs/SKILL.md) — `defineJob`, `dispatch` options, retries, progress, `find`.
|
|
25
25
|
- [`manage-failed-jobs`](@warlock.js/queue/manage-failed-jobs/SKILL.md) — `failedJobs`, `retryFailedJob`, the bull-board dashboard.
|
|
26
|
-
- [`queue-notifications`](@warlock.js/queue/queue-notifications/SKILL.md) — `
|
|
26
|
+
- [`queue-notifications`](@warlock.js/queue/queue-notifications/SKILL.md) — `bullmqQueue()` for notifications `.queue()`.
|
|
@@ -1,22 +1,23 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: queue-notifications
|
|
3
|
-
description: 'Send `@warlock.js/notifications` `.queue()` deliveries through BullMQ with `
|
|
3
|
+
description: 'Send `@warlock.js/notifications` `.queue()` deliveries through BullMQ with `bullmqQueue({ queue?, attempts?, backoff? })` from `@warlock.js/notifications` — put it in the `queue` slot of `src/config/notifications.ts`; the queue workers deliver. Honours `SendOptions.delay` (number = seconds, or "10m"), retries a failing `channel.send`, and fails at once for a channel missing from the worker config. Triggers: `bullmqQueue`, `NotificationConfig.queue`, `QueuePackageNotInstalledError`; "queue notifications with BullMQ", "retry notification delivery", "delayed notification". Skip: the herald backend — `@warlock.js/notifications/queue-notifications/SKILL.md`.'
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Queue notifications with BullMQ
|
|
7
7
|
|
|
8
8
|
```ts title="src/config/notifications.ts"
|
|
9
|
-
import { type NotificationConfig, mailChannel } from "@warlock.js/notifications";
|
|
10
|
-
import { queueNotificationDispatcher } from "@warlock.js/queue/notifications";
|
|
9
|
+
import { type NotificationConfig, bullmqQueue, mailChannel } from "@warlock.js/notifications";
|
|
11
10
|
|
|
12
11
|
const config: NotificationConfig = {
|
|
13
12
|
channels: { mail: mailChannel() },
|
|
14
|
-
queue:
|
|
13
|
+
queue: bullmqQueue({ attempts: 3, backoff: { type: "exponential", delay: 5000 } }),
|
|
15
14
|
};
|
|
16
15
|
|
|
17
16
|
export default config;
|
|
18
17
|
```
|
|
19
18
|
|
|
19
|
+
`bullmqQueue` ships inside `@warlock.js/notifications` itself and lazy-loads `@warlock.js/queue` (an OPTIONAL peer) the first time `.queue()` runs — install it with `warlock add queue` if it isn't there yet, otherwise the first `.queue()` throws `QueuePackageNotInstalledError`.
|
|
20
|
+
|
|
20
21
|
Also configure the queue itself (`configure-queue`). No separate notifications worker is needed: the delivery is an ordinary job, run by the queue workers.
|
|
21
22
|
|
|
22
23
|
```ts
|
|
@@ -31,3 +32,4 @@ await orderShipped.queue(user, { order }, { delay: "10m" }); // delivered in 10
|
|
|
31
32
|
- `channel.send` throws → retried per `attempts` / `backoff`, then listed by `failedJobs()`.
|
|
32
33
|
- Channel not configured in the worker → fails at once, no retries.
|
|
33
34
|
- Deliveries run under the job name `warlock.notifications.deliver`.
|
|
35
|
+
|