@boringnode/queue 0.2.0 → 0.3.1
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 +218 -361
- package/build/{chunk-RIXMQXYJ.js → chunk-LI2ZMCNO.js} +14 -1
- package/build/chunk-LI2ZMCNO.js.map +1 -0
- package/build/{chunk-NPQKBCCY.js → chunk-PBGPIFI5.js} +15 -1
- package/build/chunk-PBGPIFI5.js.map +1 -0
- package/build/{index-C0Xg6F4E.d.ts → index-BzPIqdx3.d.ts} +260 -3
- package/build/index.d.ts +6 -2
- package/build/index.js +218 -11
- package/build/index.js.map +1 -1
- package/build/src/contracts/adapter.d.ts +1 -1
- package/build/src/drivers/knex_adapter.d.ts +6 -3
- package/build/src/drivers/knex_adapter.js +90 -8
- package/build/src/drivers/knex_adapter.js.map +1 -1
- package/build/src/drivers/redis_adapter.d.ts +6 -3
- package/build/src/drivers/redis_adapter.js +335 -94
- package/build/src/drivers/redis_adapter.js.map +1 -1
- package/build/src/drivers/sync_adapter.d.ts +6 -3
- package/build/src/drivers/sync_adapter.js +14 -3
- package/build/src/drivers/sync_adapter.js.map +1 -1
- package/build/src/types/index.d.ts +1 -1
- package/build/src/types/main.d.ts +1 -1
- package/package.json +3 -2
- package/build/chunk-NPQKBCCY.js.map +0 -1
- package/build/chunk-RIXMQXYJ.js.map +0 -1
package/build/index.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import {
|
|
2
2
|
parse
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-PBGPIFI5.js";
|
|
4
4
|
import {
|
|
5
5
|
Locator,
|
|
6
6
|
QueueManager,
|
|
7
7
|
debug_default
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-LI2ZMCNO.js";
|
|
9
9
|
import {
|
|
10
10
|
DEFAULT_ERROR_RETRY_DELAY,
|
|
11
11
|
DEFAULT_IDLE_DELAY,
|
|
@@ -31,6 +31,7 @@ var JobDispatcher = class {
|
|
|
31
31
|
#adapter;
|
|
32
32
|
#delay;
|
|
33
33
|
#priority;
|
|
34
|
+
#groupId;
|
|
34
35
|
/**
|
|
35
36
|
* Create a new job dispatcher.
|
|
36
37
|
*
|
|
@@ -100,6 +101,28 @@ var JobDispatcher = class {
|
|
|
100
101
|
this.#priority = priority;
|
|
101
102
|
return this;
|
|
102
103
|
}
|
|
104
|
+
/**
|
|
105
|
+
* Assign this job to a group.
|
|
106
|
+
*
|
|
107
|
+
* Jobs with the same groupId can be filtered and displayed together
|
|
108
|
+
* in monitoring UIs. Useful for batch operations like newsletters
|
|
109
|
+
* or bulk exports.
|
|
110
|
+
*
|
|
111
|
+
* @param groupId - Group identifier
|
|
112
|
+
* @returns This dispatcher for chaining
|
|
113
|
+
*
|
|
114
|
+
* @example
|
|
115
|
+
* ```typescript
|
|
116
|
+
* // Group newsletter jobs together
|
|
117
|
+
* await SendEmailJob.dispatch({ to: 'user@example.com' })
|
|
118
|
+
* .group('newsletter-jan-2025')
|
|
119
|
+
* .run()
|
|
120
|
+
* ```
|
|
121
|
+
*/
|
|
122
|
+
group(groupId) {
|
|
123
|
+
this.#groupId = groupId;
|
|
124
|
+
return this;
|
|
125
|
+
}
|
|
103
126
|
/**
|
|
104
127
|
* Use a specific adapter for this job.
|
|
105
128
|
*
|
|
@@ -139,7 +162,8 @@ var JobDispatcher = class {
|
|
|
139
162
|
name: this.#name,
|
|
140
163
|
payload: this.#payload,
|
|
141
164
|
attempts: 0,
|
|
142
|
-
priority: this.#priority
|
|
165
|
+
priority: this.#priority,
|
|
166
|
+
groupId: this.#groupId
|
|
143
167
|
};
|
|
144
168
|
if (this.#delay) {
|
|
145
169
|
const parsedDelay = parse(this.#delay);
|
|
@@ -174,6 +198,144 @@ var JobDispatcher = class {
|
|
|
174
198
|
}
|
|
175
199
|
};
|
|
176
200
|
|
|
201
|
+
// src/job_batch_dispatcher.ts
|
|
202
|
+
import { randomUUID as randomUUID2 } from "crypto";
|
|
203
|
+
var JobBatchDispatcher = class {
|
|
204
|
+
#name;
|
|
205
|
+
#payloads;
|
|
206
|
+
#queue = "default";
|
|
207
|
+
#adapter;
|
|
208
|
+
#priority;
|
|
209
|
+
#groupId;
|
|
210
|
+
/**
|
|
211
|
+
* Create a new batch job dispatcher.
|
|
212
|
+
*
|
|
213
|
+
* @param name - The job class name (used to locate the class at runtime)
|
|
214
|
+
* @param payloads - Array of data to pass to each job
|
|
215
|
+
*/
|
|
216
|
+
constructor(name, payloads) {
|
|
217
|
+
this.#name = name;
|
|
218
|
+
this.#payloads = payloads;
|
|
219
|
+
}
|
|
220
|
+
/**
|
|
221
|
+
* Set the target queue for all jobs.
|
|
222
|
+
*
|
|
223
|
+
* @param queue - Queue name (default: 'default')
|
|
224
|
+
* @returns This dispatcher for chaining
|
|
225
|
+
*
|
|
226
|
+
* @example
|
|
227
|
+
* ```typescript
|
|
228
|
+
* await SendEmailJob.dispatchMany(payloads).toQueue('emails')
|
|
229
|
+
* ```
|
|
230
|
+
*/
|
|
231
|
+
toQueue(queue) {
|
|
232
|
+
this.#queue = queue;
|
|
233
|
+
return this;
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* Set the priority for all jobs.
|
|
237
|
+
*
|
|
238
|
+
* Lower numbers = higher priority. Jobs with lower priority values
|
|
239
|
+
* are processed before jobs with higher values.
|
|
240
|
+
*
|
|
241
|
+
* @param priority - Priority level (1-10, default: 5)
|
|
242
|
+
* @returns This dispatcher for chaining
|
|
243
|
+
*
|
|
244
|
+
* @example
|
|
245
|
+
* ```typescript
|
|
246
|
+
* await UrgentJob.dispatchMany(payloads).priority(1)
|
|
247
|
+
* ```
|
|
248
|
+
*/
|
|
249
|
+
priority(priority) {
|
|
250
|
+
this.#priority = priority;
|
|
251
|
+
return this;
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* Assign all jobs to a group.
|
|
255
|
+
*
|
|
256
|
+
* Jobs with the same groupId can be filtered and displayed together
|
|
257
|
+
* in monitoring UIs. Useful for batch operations like newsletters
|
|
258
|
+
* or bulk exports.
|
|
259
|
+
*
|
|
260
|
+
* @param groupId - Group identifier
|
|
261
|
+
* @returns This dispatcher for chaining
|
|
262
|
+
*
|
|
263
|
+
* @example
|
|
264
|
+
* ```typescript
|
|
265
|
+
* await SendEmailJob.dispatchMany(recipients)
|
|
266
|
+
* .group('newsletter-jan-2025')
|
|
267
|
+
* .run()
|
|
268
|
+
* ```
|
|
269
|
+
*/
|
|
270
|
+
group(groupId) {
|
|
271
|
+
this.#groupId = groupId;
|
|
272
|
+
return this;
|
|
273
|
+
}
|
|
274
|
+
/**
|
|
275
|
+
* Use a specific adapter for these jobs.
|
|
276
|
+
*
|
|
277
|
+
* @param adapter - Adapter name or factory function
|
|
278
|
+
* @returns This dispatcher for chaining
|
|
279
|
+
*
|
|
280
|
+
* @example
|
|
281
|
+
* ```typescript
|
|
282
|
+
* await Job.dispatchMany(payloads).with('redis')
|
|
283
|
+
* ```
|
|
284
|
+
*/
|
|
285
|
+
with(adapter) {
|
|
286
|
+
this.#adapter = adapter;
|
|
287
|
+
return this;
|
|
288
|
+
}
|
|
289
|
+
/**
|
|
290
|
+
* Dispatch all jobs to the queue.
|
|
291
|
+
*
|
|
292
|
+
* @returns A DispatchManyResult containing all jobIds
|
|
293
|
+
*
|
|
294
|
+
* @example
|
|
295
|
+
* ```typescript
|
|
296
|
+
* const { jobIds } = await SendEmailJob.dispatchMany(payloads).run()
|
|
297
|
+
* console.log(`Dispatched ${jobIds.length} jobs`)
|
|
298
|
+
* ```
|
|
299
|
+
*/
|
|
300
|
+
async run() {
|
|
301
|
+
debug_default("dispatching %d jobs of type %s", this.#payloads.length, this.#name);
|
|
302
|
+
const adapter = this.#getAdapterInstance();
|
|
303
|
+
const jobs = this.#payloads.map((payload) => ({
|
|
304
|
+
id: randomUUID2(),
|
|
305
|
+
name: this.#name,
|
|
306
|
+
payload,
|
|
307
|
+
attempts: 0,
|
|
308
|
+
priority: this.#priority,
|
|
309
|
+
groupId: this.#groupId
|
|
310
|
+
}));
|
|
311
|
+
await adapter.pushManyOn(this.#queue, jobs);
|
|
312
|
+
return {
|
|
313
|
+
jobIds: jobs.map((job) => job.id)
|
|
314
|
+
};
|
|
315
|
+
}
|
|
316
|
+
/**
|
|
317
|
+
* Thenable implementation for auto-dispatch when awaited.
|
|
318
|
+
*
|
|
319
|
+
* Allows `await Job.dispatchMany(payloads)` without explicit `.run()`.
|
|
320
|
+
*
|
|
321
|
+
* @param onFulfilled - Success callback
|
|
322
|
+
* @param onRejected - Error callback
|
|
323
|
+
* @returns Promise resolving to the DispatchManyResult
|
|
324
|
+
*/
|
|
325
|
+
then(onFulfilled, onRejected) {
|
|
326
|
+
return this.run().then(onFulfilled, onRejected);
|
|
327
|
+
}
|
|
328
|
+
#getAdapterInstance() {
|
|
329
|
+
if (!this.#adapter) {
|
|
330
|
+
return QueueManager.use();
|
|
331
|
+
}
|
|
332
|
+
if (typeof this.#adapter === "string") {
|
|
333
|
+
return QueueManager.use(this.#adapter);
|
|
334
|
+
}
|
|
335
|
+
return this.#adapter();
|
|
336
|
+
}
|
|
337
|
+
};
|
|
338
|
+
|
|
177
339
|
// src/schedule_builder.ts
|
|
178
340
|
import { CronExpressionParser } from "cron-parser";
|
|
179
341
|
var ScheduleBuilder = class {
|
|
@@ -461,6 +623,48 @@ var Job = class {
|
|
|
461
623
|
}
|
|
462
624
|
return dispatcher;
|
|
463
625
|
}
|
|
626
|
+
/**
|
|
627
|
+
* Dispatch multiple jobs to the queue in a single batch.
|
|
628
|
+
*
|
|
629
|
+
* Returns a JobBatchDispatcher for fluent configuration before dispatching.
|
|
630
|
+
* The jobs are not actually dispatched until `.run()` is called or the
|
|
631
|
+
* dispatcher is awaited.
|
|
632
|
+
*
|
|
633
|
+
* This is more efficient than calling `dispatch()` multiple times as it
|
|
634
|
+
* uses batched operations (e.g., Redis pipeline, SQL batch insert).
|
|
635
|
+
*
|
|
636
|
+
* @param payloads - Array of data to pass to each job
|
|
637
|
+
* @returns A JobBatchDispatcher for fluent configuration
|
|
638
|
+
*
|
|
639
|
+
* @example
|
|
640
|
+
* ```typescript
|
|
641
|
+
* // Batch dispatch for newsletter
|
|
642
|
+
* const { jobIds } = await SendEmailJob.dispatchMany([
|
|
643
|
+
* { to: 'user1@example.com', subject: 'Newsletter' },
|
|
644
|
+
* { to: 'user2@example.com', subject: 'Newsletter' },
|
|
645
|
+
* ])
|
|
646
|
+
* .group('newsletter-jan-2025')
|
|
647
|
+
* .toQueue('emails')
|
|
648
|
+
* .run()
|
|
649
|
+
*
|
|
650
|
+
* console.log(`Dispatched ${jobIds.length} jobs`)
|
|
651
|
+
* ```
|
|
652
|
+
*/
|
|
653
|
+
static dispatchMany(payloads) {
|
|
654
|
+
const options = this.options || {};
|
|
655
|
+
const jobName = options.name || this.name;
|
|
656
|
+
const dispatcher = new JobBatchDispatcher(jobName, payloads);
|
|
657
|
+
if (options.queue) {
|
|
658
|
+
dispatcher.toQueue(options.queue);
|
|
659
|
+
}
|
|
660
|
+
if (options.adapter) {
|
|
661
|
+
dispatcher.with(options.adapter);
|
|
662
|
+
}
|
|
663
|
+
if (options.priority !== void 0) {
|
|
664
|
+
dispatcher.priority(options.priority);
|
|
665
|
+
}
|
|
666
|
+
return dispatcher;
|
|
667
|
+
}
|
|
464
668
|
/**
|
|
465
669
|
* Create a schedule for this job.
|
|
466
670
|
*
|
|
@@ -494,7 +698,7 @@ var Job = class {
|
|
|
494
698
|
};
|
|
495
699
|
|
|
496
700
|
// src/worker.ts
|
|
497
|
-
import { randomUUID as
|
|
701
|
+
import { randomUUID as randomUUID3 } from "crypto";
|
|
498
702
|
import { setTimeout } from "timers/promises";
|
|
499
703
|
|
|
500
704
|
// src/job_pool.ts
|
|
@@ -600,7 +804,7 @@ var Worker = class {
|
|
|
600
804
|
*/
|
|
601
805
|
constructor(config) {
|
|
602
806
|
this.#config = config;
|
|
603
|
-
this.#id =
|
|
807
|
+
this.#id = randomUUID3();
|
|
604
808
|
this.#idleDelay = parse(config.worker?.idleDelay ?? DEFAULT_IDLE_DELAY);
|
|
605
809
|
this.#stalledInterval = parse(config.worker?.stalledInterval ?? DEFAULT_STALLED_INTERVAL);
|
|
606
810
|
this.#stalledThreshold = parse(config.worker?.stalledThreshold ?? DEFAULT_STALLED_THRESHOLD);
|
|
@@ -787,23 +991,24 @@ var Worker = class {
|
|
|
787
991
|
const startTime = performance.now();
|
|
788
992
|
debug_default("worker %s: executing job %s (%s)", this.#id, job.id, job.name);
|
|
789
993
|
const { instance, options, timeout, context, payload } = await this.#initJob(job, queue);
|
|
994
|
+
const retention = QueueManager.getMergedJobOptions(queue, options);
|
|
790
995
|
try {
|
|
791
996
|
await this.#executeWithTimeout(instance, payload, context, timeout);
|
|
792
|
-
await this.#adapter.completeJob(job.id, queue);
|
|
997
|
+
await this.#adapter.completeJob(job.id, queue, retention.removeOnComplete);
|
|
793
998
|
const duration = (performance.now() - startTime).toFixed(2);
|
|
794
999
|
debug_default("worker %s: successfully executed job %s in %dms", this.#id, job.id, duration);
|
|
795
1000
|
} catch (e) {
|
|
796
1001
|
const isTimeout = e instanceof E_JOB_TIMEOUT;
|
|
797
1002
|
if (isTimeout && options.failOnTimeout) {
|
|
798
1003
|
debug_default("worker %s: job %s timed out and failOnTimeout is set", this.#id, job.id);
|
|
799
|
-
await this.#adapter.failJob(job.id, queue, e);
|
|
1004
|
+
await this.#adapter.failJob(job.id, queue, e, retention.removeOnFail);
|
|
800
1005
|
await instance.failed?.(e);
|
|
801
1006
|
return;
|
|
802
1007
|
}
|
|
803
1008
|
const mergedConfig = QueueManager.getMergedRetryConfig(queue, options.retry);
|
|
804
1009
|
if (typeof mergedConfig.maxRetries === "undefined" || mergedConfig.maxRetries <= 0) {
|
|
805
1010
|
debug_default("worker %s: job %s has no retries configured, marking as failed", this.#id, job.id);
|
|
806
|
-
await this.#adapter.failJob(job.id, queue, e);
|
|
1011
|
+
await this.#adapter.failJob(job.id, queue, e, retention.removeOnFail);
|
|
807
1012
|
await instance.failed?.(e);
|
|
808
1013
|
return;
|
|
809
1014
|
}
|
|
@@ -814,7 +1019,7 @@ var Worker = class {
|
|
|
814
1019
|
job.id,
|
|
815
1020
|
mergedConfig.maxRetries
|
|
816
1021
|
);
|
|
817
|
-
await this.#adapter.failJob(job.id, queue, e);
|
|
1022
|
+
await this.#adapter.failJob(job.id, queue, e, retention.removeOnFail);
|
|
818
1023
|
const exception = new E_JOB_MAX_ATTEMPTS_REACHED([job.name]);
|
|
819
1024
|
await instance.failed?.(exception);
|
|
820
1025
|
return;
|
|
@@ -848,7 +1053,8 @@ var Worker = class {
|
|
|
848
1053
|
return { instance, options, timeout, context, payload: job.payload };
|
|
849
1054
|
} catch (error) {
|
|
850
1055
|
debug_default("worker %s: failed to initialize job %s (%s)", this.#id, job.id, job.name);
|
|
851
|
-
|
|
1056
|
+
const retention = QueueManager.getMergedJobOptions(queue);
|
|
1057
|
+
await this.#adapter.failJob(job.id, queue, error, retention.removeOnFail);
|
|
852
1058
|
throw error;
|
|
853
1059
|
}
|
|
854
1060
|
}
|
|
@@ -946,7 +1152,7 @@ var Worker = class {
|
|
|
946
1152
|
const JobClass = Locator.get(schedule.name);
|
|
947
1153
|
const queue = JobClass?.options?.queue ?? "default";
|
|
948
1154
|
await this.#adapter.pushOn(queue, {
|
|
949
|
-
id:
|
|
1155
|
+
id: randomUUID3(),
|
|
950
1156
|
name: schedule.name,
|
|
951
1157
|
payload: schedule.payload,
|
|
952
1158
|
attempts: 0,
|
|
@@ -1223,6 +1429,7 @@ function customBackoff(config) {
|
|
|
1223
1429
|
}
|
|
1224
1430
|
export {
|
|
1225
1431
|
Job,
|
|
1432
|
+
JobBatchDispatcher,
|
|
1226
1433
|
Locator,
|
|
1227
1434
|
QueueManager,
|
|
1228
1435
|
Schedule,
|