@basaltkit/queue 1.0.0 → 1.1.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/LICENSE +1 -1
- package/dist/index.d.ts +43 -1
- package/dist/index.js +33 -7
- package/package.json +1 -1
package/LICENSE
CHANGED
package/dist/index.d.ts
CHANGED
|
@@ -3,6 +3,11 @@ import { DurationInput, BasaltError } from '@basaltkit/core';
|
|
|
3
3
|
import { ConnectionOptions } from 'bullmq';
|
|
4
4
|
import { EventBus, BasaltEvent } from '@basaltkit/events';
|
|
5
5
|
|
|
6
|
+
/** Driver-neutral retention: `true`/`false`, a count, or `{ ageMs, count }`. */
|
|
7
|
+
type RetentionOption = boolean | number | {
|
|
8
|
+
ageMs?: number;
|
|
9
|
+
count?: number;
|
|
10
|
+
};
|
|
6
11
|
interface AddJobOptions {
|
|
7
12
|
attempts: number;
|
|
8
13
|
backoff?: {
|
|
@@ -11,6 +16,10 @@ interface AddJobOptions {
|
|
|
11
16
|
} | undefined;
|
|
12
17
|
delayMs?: number | undefined;
|
|
13
18
|
priority?: number | undefined;
|
|
19
|
+
/** Retention for completed jobs. Undefined → the driver's default. */
|
|
20
|
+
removeOnComplete?: RetentionOption | undefined;
|
|
21
|
+
/** Retention for failed jobs. Undefined → the driver's default. */
|
|
22
|
+
removeOnFail?: RetentionOption | undefined;
|
|
14
23
|
}
|
|
15
24
|
type JobExecutor = (jobName: string, data: unknown) => Promise<void>;
|
|
16
25
|
/**
|
|
@@ -96,12 +105,26 @@ interface JobBackoff {
|
|
|
96
105
|
type: 'exponential' | 'fixed';
|
|
97
106
|
delay: DurationInput;
|
|
98
107
|
}
|
|
108
|
+
/**
|
|
109
|
+
* Redis retention for finished jobs (BullMQ driver): `true` removes it as soon as
|
|
110
|
+
* it finishes, `false` keeps it forever, a number keeps that many most-recent, and
|
|
111
|
+
* `{ age, count }` keeps by age and/or count. Defaults: completed `{ count: 1000 }`,
|
|
112
|
+
* failed `false` (keep all). The sync driver ignores it (it stores nothing).
|
|
113
|
+
*/
|
|
114
|
+
type JobRetention = boolean | number | {
|
|
115
|
+
age?: DurationInput;
|
|
116
|
+
count?: number;
|
|
117
|
+
};
|
|
99
118
|
interface JobDefinition<T = unknown> {
|
|
100
119
|
readonly name: string;
|
|
101
120
|
readonly schema?: JobSchema<T> | undefined;
|
|
102
121
|
readonly queue: string;
|
|
103
122
|
readonly attempts: number;
|
|
104
123
|
readonly backoff?: JobBackoff | undefined;
|
|
124
|
+
/** Retention for completed jobs. Overrides the queuePlugin default. */
|
|
125
|
+
readonly removeOnComplete?: JobRetention | undefined;
|
|
126
|
+
/** Retention for failed jobs. Overrides the queuePlugin default. */
|
|
127
|
+
readonly removeOnFail?: JobRetention | undefined;
|
|
105
128
|
handle(payload: T): void | Promise<void>;
|
|
106
129
|
/** Enqueues the job — available after registration in a QueueManager. */
|
|
107
130
|
dispatch(payload: T, options?: DispatchOptions): Promise<void>;
|
|
@@ -128,6 +151,8 @@ declare function defineJob<T = unknown>(config: {
|
|
|
128
151
|
queue?: string;
|
|
129
152
|
attempts?: number;
|
|
130
153
|
backoff?: JobBackoff;
|
|
154
|
+
removeOnComplete?: JobRetention;
|
|
155
|
+
removeOnFail?: JobRetention;
|
|
131
156
|
handle(payload: T): void | Promise<void>;
|
|
132
157
|
}): JobDefinition<T>;
|
|
133
158
|
|
|
@@ -151,6 +176,10 @@ interface QueueManagerOptions {
|
|
|
151
176
|
onUnsupported?: UnsupportedPolicy;
|
|
152
177
|
/** Sink for 'warn' diagnostics. Default console.warn. */
|
|
153
178
|
warn?: (message: string) => void;
|
|
179
|
+
/** Default retention for completed jobs (a job can override). Driver default: keep 1000. */
|
|
180
|
+
removeOnComplete?: JobRetention;
|
|
181
|
+
/** Default retention for failed jobs (a job can override). Driver default: keep all. */
|
|
182
|
+
removeOnFail?: JobRetention;
|
|
154
183
|
}
|
|
155
184
|
declare class QueueManager implements JobDispatcher {
|
|
156
185
|
private readonly driver;
|
|
@@ -158,6 +187,8 @@ declare class QueueManager implements JobDispatcher {
|
|
|
158
187
|
private readonly onUnsupported;
|
|
159
188
|
private readonly warn;
|
|
160
189
|
private readonly warned;
|
|
190
|
+
private readonly defaultRemoveOnComplete;
|
|
191
|
+
private readonly defaultRemoveOnFail;
|
|
161
192
|
constructor(driver: QueueDriver, options?: QueueManagerOptions);
|
|
162
193
|
/**
|
|
163
194
|
* Checks the dispatch's options against the driver's declared capabilities.
|
|
@@ -236,7 +267,18 @@ interface QueuePluginOptions {
|
|
|
236
267
|
* 'throw' in production for a hard guarantee, 'ignore' for the old behavior.
|
|
237
268
|
*/
|
|
238
269
|
onUnsupported?: UnsupportedPolicy;
|
|
270
|
+
/**
|
|
271
|
+
* Default retention for completed jobs in Redis (BullMQ). `true` removes on
|
|
272
|
+
* finish, a number keeps that many, `{ age: '7d', count: 500 }` caps both.
|
|
273
|
+
* Default: keep the last 1000. A job can override via `defineJob`.
|
|
274
|
+
*/
|
|
275
|
+
removeOnComplete?: JobRetention;
|
|
276
|
+
/**
|
|
277
|
+
* Default retention for failed jobs. Default `false` (keep all, for inspection
|
|
278
|
+
* and retries) — set e.g. `{ age: '14d' }` so failures don't grow unbounded.
|
|
279
|
+
*/
|
|
280
|
+
removeOnFail?: JobRetention;
|
|
239
281
|
}
|
|
240
282
|
declare function queuePlugin(options?: QueuePluginOptions): _basaltkit_core.BasaltPlugin<unknown>;
|
|
241
283
|
|
|
242
|
-
export { type AddJobOptions, type BullmqDriverOptions, BullmqQueueDriver, type DispatchOptions, type DriverCapabilities, type JobBackoff, type JobDefinition, type JobExecutor, JobNotRegisteredError, type JobSchema, JobValidationError, QUEUE, type QueueDriver, QueueManager, type QueueManagerOptions, type QueuePluginOptions, type QueuedListenerOptions, SyncQueueDriver, UnknownJobError, UnsupportedJobOptionError, type UnsupportedPolicy, defineJob, queuePlugin, queuedOn };
|
|
284
|
+
export { type AddJobOptions, type BullmqDriverOptions, BullmqQueueDriver, type DispatchOptions, type DriverCapabilities, type JobBackoff, type JobDefinition, type JobExecutor, JobNotRegisteredError, type JobRetention, type JobSchema, JobValidationError, QUEUE, type QueueDriver, QueueManager, type QueueManagerOptions, type QueuePluginOptions, type QueuedListenerOptions, SyncQueueDriver, UnknownJobError, UnsupportedJobOptionError, type UnsupportedPolicy, defineJob, queuePlugin, queuedOn };
|
package/dist/index.js
CHANGED
|
@@ -3,6 +3,14 @@ import { createToken, definePlugin } from "@basaltkit/core";
|
|
|
3
3
|
|
|
4
4
|
// src/drivers/bullmq.ts
|
|
5
5
|
import { Queue, Worker } from "bullmq";
|
|
6
|
+
function toBullRetention(retention, fallback) {
|
|
7
|
+
if (retention === void 0) return fallback;
|
|
8
|
+
if (typeof retention === "boolean" || typeof retention === "number") return retention;
|
|
9
|
+
const out = {};
|
|
10
|
+
if (retention.ageMs !== void 0) out.age = Math.max(1, Math.round(retention.ageMs / 1e3));
|
|
11
|
+
if (retention.count !== void 0) out.count = retention.count;
|
|
12
|
+
return out;
|
|
13
|
+
}
|
|
6
14
|
var BullmqQueueDriver = class {
|
|
7
15
|
name = "bullmq";
|
|
8
16
|
capabilities = { delayed: true, priority: true, retries: true, backoff: true };
|
|
@@ -22,8 +30,8 @@ var BullmqQueueDriver = class {
|
|
|
22
30
|
...options.backoff ? { backoff: { type: options.backoff.type, delay: options.backoff.delayMs } } : {},
|
|
23
31
|
...options.delayMs !== void 0 ? { delay: options.delayMs } : {},
|
|
24
32
|
...options.priority !== void 0 ? { priority: options.priority } : {},
|
|
25
|
-
removeOnComplete: { count: 1e3 },
|
|
26
|
-
removeOnFail: false
|
|
33
|
+
removeOnComplete: toBullRetention(options.removeOnComplete, { count: 1e3 }),
|
|
34
|
+
removeOnFail: toBullRetention(options.removeOnFail, false)
|
|
27
35
|
});
|
|
28
36
|
}
|
|
29
37
|
startWorker(queue, options = {}) {
|
|
@@ -128,6 +136,8 @@ function defineJob(config) {
|
|
|
128
136
|
queue: config.queue ?? "default",
|
|
129
137
|
attempts: config.attempts ?? 1,
|
|
130
138
|
backoff: config.backoff,
|
|
139
|
+
removeOnComplete: config.removeOnComplete,
|
|
140
|
+
removeOnFail: config.removeOnFail,
|
|
131
141
|
handle: config.handle,
|
|
132
142
|
async dispatch(payload, options) {
|
|
133
143
|
if (!dispatcher) throw new JobNotRegisteredError(config.name);
|
|
@@ -150,6 +160,14 @@ function validatePayload(job, payload) {
|
|
|
150
160
|
}
|
|
151
161
|
|
|
152
162
|
// src/manager.ts
|
|
163
|
+
function resolveRetention(retention) {
|
|
164
|
+
if (retention === void 0) return void 0;
|
|
165
|
+
if (typeof retention === "boolean" || typeof retention === "number") return retention;
|
|
166
|
+
const out = {};
|
|
167
|
+
if (retention.age !== void 0) out.ageMs = parseDuration(retention.age);
|
|
168
|
+
if (retention.count !== void 0) out.count = retention.count;
|
|
169
|
+
return out;
|
|
170
|
+
}
|
|
153
171
|
var UnknownJobError = class extends BasaltError2 {
|
|
154
172
|
constructor(job) {
|
|
155
173
|
super(
|
|
@@ -187,6 +205,8 @@ var QueueManager = class {
|
|
|
187
205
|
this.driver = driver;
|
|
188
206
|
this.onUnsupported = options.onUnsupported ?? "warn";
|
|
189
207
|
this.warn = options.warn ?? ((message) => console.warn(message));
|
|
208
|
+
this.defaultRemoveOnComplete = options.removeOnComplete;
|
|
209
|
+
this.defaultRemoveOnFail = options.removeOnFail;
|
|
190
210
|
driver.setExecutor((jobName, data) => this.execute(jobName, data));
|
|
191
211
|
}
|
|
192
212
|
driver;
|
|
@@ -194,6 +214,8 @@ var QueueManager = class {
|
|
|
194
214
|
onUnsupported;
|
|
195
215
|
warn;
|
|
196
216
|
warned = /* @__PURE__ */ new Set();
|
|
217
|
+
defaultRemoveOnComplete;
|
|
218
|
+
defaultRemoveOnFail;
|
|
197
219
|
/**
|
|
198
220
|
* Checks the dispatch's options against the driver's declared capabilities.
|
|
199
221
|
* A driver that omits `capabilities` is assumed fully capable (back-compat).
|
|
@@ -228,7 +250,10 @@ var QueueManager = class {
|
|
|
228
250
|
attempts: job.attempts,
|
|
229
251
|
backoff: job.backoff ? { type: job.backoff.type, delayMs: parseDuration(job.backoff.delay) } : void 0,
|
|
230
252
|
delayMs: options.delay === void 0 ? void 0 : parseDuration(options.delay),
|
|
231
|
-
priority: options.priority
|
|
253
|
+
priority: options.priority,
|
|
254
|
+
// Per-job overrides the queuePlugin default; undefined leaves the driver default.
|
|
255
|
+
removeOnComplete: resolveRetention(job.removeOnComplete ?? this.defaultRemoveOnComplete),
|
|
256
|
+
removeOnFail: resolveRetention(job.removeOnFail ?? this.defaultRemoveOnFail)
|
|
232
257
|
};
|
|
233
258
|
this.assertSupported(job.name, addOptions);
|
|
234
259
|
await this.driver.add(job.queue, job.name, envelope, addOptions);
|
|
@@ -287,10 +312,11 @@ function queuePlugin(options = {}) {
|
|
|
287
312
|
register({ container }) {
|
|
288
313
|
container.singleton(QUEUE, () => {
|
|
289
314
|
const driver = options.driver ?? (options.connection ? new BullmqQueueDriver({ connection: options.connection }) : new SyncQueueDriver());
|
|
290
|
-
const manager = new QueueManager(
|
|
291
|
-
|
|
292
|
-
options.
|
|
293
|
-
|
|
315
|
+
const manager = new QueueManager(driver, {
|
|
316
|
+
...options.onUnsupported !== void 0 ? { onUnsupported: options.onUnsupported } : {},
|
|
317
|
+
...options.removeOnComplete !== void 0 ? { removeOnComplete: options.removeOnComplete } : {},
|
|
318
|
+
...options.removeOnFail !== void 0 ? { removeOnFail: options.removeOnFail } : {}
|
|
319
|
+
});
|
|
294
320
|
for (const job of options.jobs ?? []) manager.register(job);
|
|
295
321
|
return manager;
|
|
296
322
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@basaltkit/queue",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "Basalt queues on top of BullMQ: declarative jobs with Zod payloads, context propagation (tenant/requestId) to workers and a sync driver for tests.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|