@boringnode/queue 0.0.1-alpha.2 → 0.0.1-alpha.4
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 +145 -34
- package/build/chunk-5PDDRF5O.js +26 -0
- package/build/chunk-5PDDRF5O.js.map +1 -0
- package/build/chunk-CD45GT6E.js +357 -0
- package/build/chunk-CD45GT6E.js.map +1 -0
- package/build/chunk-HMGNQSSG.js +103 -0
- package/build/chunk-HMGNQSSG.js.map +1 -0
- package/build/index-C3_tlebh.d.ts +776 -0
- package/build/index.d.ts +352 -4
- package/build/index.js +526 -137
- package/build/index.js.map +1 -1
- package/build/src/contracts/adapter.d.ts +1 -1
- package/build/src/drivers/knex_adapter.d.ts +2 -1
- package/build/src/drivers/knex_adapter.js +76 -17
- package/build/src/drivers/knex_adapter.js.map +1 -1
- package/build/src/drivers/redis_adapter.d.ts +2 -2
- package/build/src/drivers/redis_adapter.js +74 -27
- package/build/src/drivers/redis_adapter.js.map +1 -1
- package/build/src/drivers/sync_adapter.d.ts +7 -3
- package/build/src/drivers/sync_adapter.js +27 -7
- package/build/src/drivers/sync_adapter.js.map +1 -1
- package/build/src/types/index.d.ts +1 -0
- package/build/src/types/index.js +1 -0
- package/build/src/types/index.js.map +1 -0
- package/build/src/types/main.d.ts +1 -1
- package/package.json +20 -15
- package/build/job-Bd_c2lFK.d.ts +0 -149
|
@@ -0,0 +1,776 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Calculates retry delays using configurable strategies.
|
|
3
|
+
*
|
|
4
|
+
* Supports three built-in strategies:
|
|
5
|
+
* - `exponential`: Delay doubles each attempt (1s, 2s, 4s, 8s, ...)
|
|
6
|
+
* - `linear`: Delay increases linearly (5s, 10s, 15s, 20s, ...)
|
|
7
|
+
* - `fixed`: Same delay every time (10s, 10s, 10s, ...)
|
|
8
|
+
*
|
|
9
|
+
* All strategies support:
|
|
10
|
+
* - `maxDelay`: Cap the maximum delay
|
|
11
|
+
* - `jitter`: Add randomness to prevent thundering herd
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```typescript
|
|
15
|
+
* const strategy = new BackoffStrategy({
|
|
16
|
+
* strategy: 'exponential',
|
|
17
|
+
* baseDelay: '1s',
|
|
18
|
+
* maxDelay: '5m',
|
|
19
|
+
* multiplier: 2,
|
|
20
|
+
* jitter: true,
|
|
21
|
+
* })
|
|
22
|
+
*
|
|
23
|
+
* strategy.calculateDelay(1) // ~1000ms
|
|
24
|
+
* strategy.calculateDelay(2) // ~2000ms
|
|
25
|
+
* strategy.calculateDelay(3) // ~4000ms
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
28
|
+
declare class BackoffStrategy$1 {
|
|
29
|
+
#private;
|
|
30
|
+
/**
|
|
31
|
+
* Create a new backoff strategy.
|
|
32
|
+
*
|
|
33
|
+
* @param config - Backoff configuration
|
|
34
|
+
* @throws {E_INVALID_BASE_DELAY} If baseDelay is not positive
|
|
35
|
+
* @throws {E_INVALID_MAX_DELAY} If maxDelay is invalid
|
|
36
|
+
* @throws {E_INVALID_MULTIPLIER} If multiplier is invalid
|
|
37
|
+
*/
|
|
38
|
+
constructor(config: BackoffConfig);
|
|
39
|
+
/**
|
|
40
|
+
* Calculate the delay for a given attempt number.
|
|
41
|
+
*
|
|
42
|
+
* @param attempt - The attempt number (1-based)
|
|
43
|
+
* @returns Delay in milliseconds
|
|
44
|
+
* @throws {RuntimeException} If attempt is less than 1
|
|
45
|
+
*
|
|
46
|
+
* @example
|
|
47
|
+
* ```typescript
|
|
48
|
+
* // Exponential: 1s, 2s, 4s, 8s, 16s, ...
|
|
49
|
+
* strategy.calculateDelay(1) // 1000
|
|
50
|
+
* strategy.calculateDelay(2) // 2000
|
|
51
|
+
* strategy.calculateDelay(3) // 4000
|
|
52
|
+
* ```
|
|
53
|
+
*/
|
|
54
|
+
calculateDelay(attempt: number): number;
|
|
55
|
+
/**
|
|
56
|
+
* Get the Date when the next retry should occur.
|
|
57
|
+
*
|
|
58
|
+
* @param attempt - The attempt number (1-based)
|
|
59
|
+
* @returns Date for the next retry
|
|
60
|
+
*
|
|
61
|
+
* @example
|
|
62
|
+
* ```typescript
|
|
63
|
+
* const nextRetry = strategy.getNextRetryAt(3)
|
|
64
|
+
* console.log(`Retry at: ${nextRetry.toISOString()}`)
|
|
65
|
+
* ```
|
|
66
|
+
*/
|
|
67
|
+
getNextRetryAt(attempt: number): Date;
|
|
68
|
+
/**
|
|
69
|
+
* Get a frozen copy of the configuration.
|
|
70
|
+
*
|
|
71
|
+
* @returns Readonly configuration object
|
|
72
|
+
*/
|
|
73
|
+
getConfig(): Readonly<BackoffConfig>;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Create an exponential backoff strategy factory.
|
|
77
|
+
*
|
|
78
|
+
* Delay doubles with each attempt: 1s → 2s → 4s → 8s → ...
|
|
79
|
+
*
|
|
80
|
+
* Default config:
|
|
81
|
+
* - baseDelay: 1s
|
|
82
|
+
* - maxDelay: 5m
|
|
83
|
+
* - multiplier: 2
|
|
84
|
+
* - jitter: true
|
|
85
|
+
*
|
|
86
|
+
* @param config - Optional overrides for default config
|
|
87
|
+
* @returns Factory function for creating BackoffStrategy instances
|
|
88
|
+
*
|
|
89
|
+
* @example
|
|
90
|
+
* ```typescript
|
|
91
|
+
* const config = {
|
|
92
|
+
* retry: {
|
|
93
|
+
* maxRetries: 5,
|
|
94
|
+
* backoff: exponentialBackoff({ baseDelay: '500ms', maxDelay: '1m' }),
|
|
95
|
+
* },
|
|
96
|
+
* }
|
|
97
|
+
* ```
|
|
98
|
+
*/
|
|
99
|
+
declare function exponentialBackoff(config?: Partial<Omit<BackoffConfig, 'strategy'>>): () => BackoffStrategy$1;
|
|
100
|
+
/**
|
|
101
|
+
* Create a linear backoff strategy factory.
|
|
102
|
+
*
|
|
103
|
+
* Delay increases linearly: 5s → 10s → 15s → 20s → ...
|
|
104
|
+
*
|
|
105
|
+
* Default config:
|
|
106
|
+
* - baseDelay: 5s
|
|
107
|
+
* - maxDelay: 2m
|
|
108
|
+
*
|
|
109
|
+
* @param config - Optional overrides for default config
|
|
110
|
+
* @returns Factory function for creating BackoffStrategy instances
|
|
111
|
+
*
|
|
112
|
+
* @example
|
|
113
|
+
* ```typescript
|
|
114
|
+
* const config = {
|
|
115
|
+
* retry: {
|
|
116
|
+
* maxRetries: 3,
|
|
117
|
+
* backoff: linearBackoff({ baseDelay: '10s' }),
|
|
118
|
+
* },
|
|
119
|
+
* }
|
|
120
|
+
* ```
|
|
121
|
+
*/
|
|
122
|
+
declare function linearBackoff(config?: Partial<Omit<BackoffConfig, 'strategy'>>): () => BackoffStrategy$1;
|
|
123
|
+
/**
|
|
124
|
+
* Create a fixed delay backoff strategy factory.
|
|
125
|
+
*
|
|
126
|
+
* Same delay every time: 10s → 10s → 10s → ...
|
|
127
|
+
*
|
|
128
|
+
* @param delay - The fixed delay (default: '10s')
|
|
129
|
+
* @returns Factory function for creating BackoffStrategy instances
|
|
130
|
+
*
|
|
131
|
+
* @example
|
|
132
|
+
* ```typescript
|
|
133
|
+
* const config = {
|
|
134
|
+
* retry: {
|
|
135
|
+
* maxRetries: 3,
|
|
136
|
+
* backoff: fixedBackoff('30s'),
|
|
137
|
+
* },
|
|
138
|
+
* }
|
|
139
|
+
* ```
|
|
140
|
+
*/
|
|
141
|
+
declare function fixedBackoff(delay?: Duration): () => BackoffStrategy$1;
|
|
142
|
+
/**
|
|
143
|
+
* Create a custom backoff strategy factory.
|
|
144
|
+
*
|
|
145
|
+
* Use this when you need full control over the configuration.
|
|
146
|
+
*
|
|
147
|
+
* @param config - Complete backoff configuration
|
|
148
|
+
* @returns Factory function for creating BackoffStrategy instances
|
|
149
|
+
*
|
|
150
|
+
* @example
|
|
151
|
+
* ```typescript
|
|
152
|
+
* const config = {
|
|
153
|
+
* retry: {
|
|
154
|
+
* maxRetries: 5,
|
|
155
|
+
* backoff: customBackoff({
|
|
156
|
+
* strategy: 'exponential',
|
|
157
|
+
* baseDelay: '100ms',
|
|
158
|
+
* maxDelay: '30s',
|
|
159
|
+
* multiplier: 3,
|
|
160
|
+
* jitter: false,
|
|
161
|
+
* }),
|
|
162
|
+
* },
|
|
163
|
+
* }
|
|
164
|
+
* ```
|
|
165
|
+
*/
|
|
166
|
+
declare function customBackoff(config: BackoffConfig): () => BackoffStrategy$1;
|
|
167
|
+
|
|
168
|
+
interface LogObject {
|
|
169
|
+
[key: string]: unknown;
|
|
170
|
+
}
|
|
171
|
+
interface ErrorObject extends LogObject {
|
|
172
|
+
err?: Error;
|
|
173
|
+
}
|
|
174
|
+
interface Logger {
|
|
175
|
+
trace(msg: string): void;
|
|
176
|
+
trace(obj: LogObject, msg: string): void;
|
|
177
|
+
debug(msg: string): void;
|
|
178
|
+
debug(obj: LogObject, msg: string): void;
|
|
179
|
+
info(msg: string): void;
|
|
180
|
+
info(obj: LogObject, msg: string): void;
|
|
181
|
+
warn(msg: string): void;
|
|
182
|
+
warn(obj: LogObject, msg: string): void;
|
|
183
|
+
error(msg: string): void;
|
|
184
|
+
error(obj: ErrorObject, msg: string): void;
|
|
185
|
+
child(obj: LogObject): Logger;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
type Duration = number | string;
|
|
189
|
+
interface JobData {
|
|
190
|
+
id: string;
|
|
191
|
+
name: string;
|
|
192
|
+
payload: any;
|
|
193
|
+
attempts: number;
|
|
194
|
+
priority?: number;
|
|
195
|
+
nextRetryAt?: Date;
|
|
196
|
+
stalledCount?: number;
|
|
197
|
+
}
|
|
198
|
+
interface JobOptions {
|
|
199
|
+
queue?: string;
|
|
200
|
+
adapter?: string | (() => Adapter);
|
|
201
|
+
maxRetries?: number;
|
|
202
|
+
priority?: number;
|
|
203
|
+
retry?: RetryConfig;
|
|
204
|
+
timeout?: Duration;
|
|
205
|
+
failOnTimeout?: boolean;
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
* Context information available to a job during execution.
|
|
209
|
+
*
|
|
210
|
+
* Provides metadata about the current job execution, including
|
|
211
|
+
* retry information, queue details, and timing.
|
|
212
|
+
*
|
|
213
|
+
* @example
|
|
214
|
+
* ```typescript
|
|
215
|
+
* class MyJob extends Job<Payload> {
|
|
216
|
+
* async execute() {
|
|
217
|
+
* console.log(`Attempt ${this.context.attempt} of job ${this.context.jobId}`)
|
|
218
|
+
* console.log(`Running on queue: ${this.context.queue}`)
|
|
219
|
+
* }
|
|
220
|
+
* }
|
|
221
|
+
* ```
|
|
222
|
+
*/
|
|
223
|
+
interface JobContext {
|
|
224
|
+
/** Unique identifier for this job */
|
|
225
|
+
jobId: string;
|
|
226
|
+
/** Job class name */
|
|
227
|
+
name: string;
|
|
228
|
+
/** Current attempt number (1-based: first attempt = 1) */
|
|
229
|
+
attempt: number;
|
|
230
|
+
/** Queue name this job is being processed from */
|
|
231
|
+
queue: string;
|
|
232
|
+
/** Job priority (lower number = higher priority) */
|
|
233
|
+
priority: number;
|
|
234
|
+
/** When this job was acquired by the worker for processing */
|
|
235
|
+
acquiredAt: Date;
|
|
236
|
+
/** Number of times this job has been recovered from stalled state */
|
|
237
|
+
stalledCount: number;
|
|
238
|
+
}
|
|
239
|
+
type JobClass<T extends Job = Job> = (new (payload: any, context: JobContext) => T) & {
|
|
240
|
+
options?: JobOptions;
|
|
241
|
+
};
|
|
242
|
+
/**
|
|
243
|
+
* Factory function for custom job instantiation.
|
|
244
|
+
*
|
|
245
|
+
* Use this to integrate with IoC containers for dependency injection.
|
|
246
|
+
* The factory receives the job class, payload, and context, and must return
|
|
247
|
+
* a job instance (or a Promise that resolves to one).
|
|
248
|
+
*
|
|
249
|
+
* @param JobClass - The job class to instantiate
|
|
250
|
+
* @param payload - The payload data for the job
|
|
251
|
+
* @param context - The job execution context (jobId, attempt, queue, etc.)
|
|
252
|
+
* @returns The job instance, or a Promise resolving to the instance
|
|
253
|
+
*
|
|
254
|
+
* @example
|
|
255
|
+
* ```typescript
|
|
256
|
+
* // With AdonisJS IoC container
|
|
257
|
+
* const worker = new Worker({
|
|
258
|
+
* worker: {
|
|
259
|
+
* jobFactory: async (JobClass, payload, context) => {
|
|
260
|
+
* return app.container.make(JobClass, [payload, context])
|
|
261
|
+
* }
|
|
262
|
+
* }
|
|
263
|
+
* })
|
|
264
|
+
* ```
|
|
265
|
+
*/
|
|
266
|
+
type JobFactory = (JobClass: JobClass, payload: any, context: JobContext) => Job | Promise<Job>;
|
|
267
|
+
interface RetryConfig {
|
|
268
|
+
maxRetries?: number;
|
|
269
|
+
backoff?: () => BackoffStrategy$1;
|
|
270
|
+
}
|
|
271
|
+
type BackoffStrategy = 'exponential' | 'linear' | 'fixed';
|
|
272
|
+
interface BackoffConfig {
|
|
273
|
+
strategy: BackoffStrategy;
|
|
274
|
+
baseDelay: Duration;
|
|
275
|
+
maxDelay?: Duration;
|
|
276
|
+
multiplier?: number;
|
|
277
|
+
jitter?: boolean;
|
|
278
|
+
}
|
|
279
|
+
interface QueueConfig {
|
|
280
|
+
adapter?: string;
|
|
281
|
+
retry?: any;
|
|
282
|
+
}
|
|
283
|
+
interface WorkerConfig {
|
|
284
|
+
/**
|
|
285
|
+
* Maximum number of jobs to process concurrently.
|
|
286
|
+
* @default 1
|
|
287
|
+
*/
|
|
288
|
+
concurrency?: number;
|
|
289
|
+
/**
|
|
290
|
+
* Delay between queue polls when idle (no jobs available).
|
|
291
|
+
* @default '2s'
|
|
292
|
+
*/
|
|
293
|
+
idleDelay?: Duration;
|
|
294
|
+
/**
|
|
295
|
+
* Maximum duration a job can run before being timed out.
|
|
296
|
+
* Can be overridden per job via JobOptions.timeout.
|
|
297
|
+
* @default undefined (no timeout)
|
|
298
|
+
*/
|
|
299
|
+
timeout?: Duration;
|
|
300
|
+
/**
|
|
301
|
+
* Duration after which an active job is considered stalled.
|
|
302
|
+
* A stalled job is one that was acquired but the worker stopped
|
|
303
|
+
* responding (e.g., due to a crash).
|
|
304
|
+
* @default '30s'
|
|
305
|
+
*/
|
|
306
|
+
stalledThreshold?: Duration;
|
|
307
|
+
/**
|
|
308
|
+
* How often to check for stalled jobs.
|
|
309
|
+
* @default '30s'
|
|
310
|
+
*/
|
|
311
|
+
stalledInterval?: Duration;
|
|
312
|
+
/**
|
|
313
|
+
* Maximum number of times a job can be recovered from stalled state
|
|
314
|
+
* before being marked as failed permanently.
|
|
315
|
+
* @default 1
|
|
316
|
+
*/
|
|
317
|
+
maxStalledCount?: number;
|
|
318
|
+
/**
|
|
319
|
+
* Whether to automatically stop the worker on SIGINT/SIGTERM signals.
|
|
320
|
+
* When enabled, the worker will wait for running jobs to complete
|
|
321
|
+
* before stopping.
|
|
322
|
+
* @default true
|
|
323
|
+
*/
|
|
324
|
+
gracefulShutdown?: boolean;
|
|
325
|
+
/**
|
|
326
|
+
* Callback invoked when a shutdown signal is received.
|
|
327
|
+
* Called before the worker starts stopping.
|
|
328
|
+
*/
|
|
329
|
+
onShutdownSignal?: () => void | Promise<void>;
|
|
330
|
+
}
|
|
331
|
+
type WorkerCycle = {
|
|
332
|
+
type: 'started';
|
|
333
|
+
queue: string;
|
|
334
|
+
job: any;
|
|
335
|
+
} | {
|
|
336
|
+
type: 'completed';
|
|
337
|
+
queue: string;
|
|
338
|
+
job: any;
|
|
339
|
+
} | {
|
|
340
|
+
type: 'idle';
|
|
341
|
+
suggestedDelay: Duration;
|
|
342
|
+
} | {
|
|
343
|
+
type: 'error';
|
|
344
|
+
error: Error;
|
|
345
|
+
suggestedDelay: Duration;
|
|
346
|
+
};
|
|
347
|
+
type AdapterFactory<T extends Adapter = Adapter> = () => T;
|
|
348
|
+
interface QueueManagerConfig {
|
|
349
|
+
default: string;
|
|
350
|
+
adapters: Record<string, AdapterFactory>;
|
|
351
|
+
retry?: RetryConfig;
|
|
352
|
+
queues?: Record<string, QueueConfig>;
|
|
353
|
+
worker?: WorkerConfig;
|
|
354
|
+
locations?: string[];
|
|
355
|
+
logger?: Logger;
|
|
356
|
+
/**
|
|
357
|
+
* Custom factory function for job instantiation.
|
|
358
|
+
*
|
|
359
|
+
* Use this to integrate with IoC containers for dependency injection.
|
|
360
|
+
* When provided, this factory is called instead of `new JobClass(payload, context)`.
|
|
361
|
+
*
|
|
362
|
+
* @example
|
|
363
|
+
* ```typescript
|
|
364
|
+
* await QueueManager.init({
|
|
365
|
+
* default: 'redis',
|
|
366
|
+
* adapters: { redis: redis() },
|
|
367
|
+
* jobFactory: async (JobClass, payload, context) => {
|
|
368
|
+
* return app.container.make(JobClass, [payload, context])
|
|
369
|
+
* }
|
|
370
|
+
* })
|
|
371
|
+
* ```
|
|
372
|
+
*/
|
|
373
|
+
jobFactory?: JobFactory;
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
/**
|
|
377
|
+
* A job that has been acquired by a worker for processing.
|
|
378
|
+
* Extends JobData with the timestamp when the job was acquired.
|
|
379
|
+
*/
|
|
380
|
+
interface AcquiredJob extends JobData {
|
|
381
|
+
/** Timestamp (in ms) when the job was acquired by the worker */
|
|
382
|
+
acquiredAt: number;
|
|
383
|
+
}
|
|
384
|
+
/**
|
|
385
|
+
* Adapter interface for queue storage backends.
|
|
386
|
+
*
|
|
387
|
+
* Implementations handle job persistence, atomic operations, and
|
|
388
|
+
* concurrency control. Built-in adapters: Redis, Knex (PostgreSQL/SQLite).
|
|
389
|
+
*
|
|
390
|
+
* @example
|
|
391
|
+
* ```typescript
|
|
392
|
+
* import { redis } from '@boringnode/queue'
|
|
393
|
+
*
|
|
394
|
+
* const config = {
|
|
395
|
+
* default: 'redis',
|
|
396
|
+
* adapters: {
|
|
397
|
+
* redis: redis({ host: 'localhost', port: 6379 })
|
|
398
|
+
* }
|
|
399
|
+
* }
|
|
400
|
+
* ```
|
|
401
|
+
*/
|
|
402
|
+
interface Adapter {
|
|
403
|
+
/**
|
|
404
|
+
* Set the worker ID for this adapter instance.
|
|
405
|
+
* Required before calling pop methods when consuming jobs.
|
|
406
|
+
*
|
|
407
|
+
* @param workerId - Unique identifier for the worker
|
|
408
|
+
*/
|
|
409
|
+
setWorkerId(workerId: string): void;
|
|
410
|
+
/**
|
|
411
|
+
* Pop the next available job from the default queue.
|
|
412
|
+
* Atomically moves the job from pending to active state.
|
|
413
|
+
*
|
|
414
|
+
* @returns The acquired job, or null if queue is empty
|
|
415
|
+
*/
|
|
416
|
+
pop(): Promise<AcquiredJob | null>;
|
|
417
|
+
/**
|
|
418
|
+
* Pop the next available job from a specific queue.
|
|
419
|
+
* Atomically moves the job from pending to active state.
|
|
420
|
+
*
|
|
421
|
+
* @param queue - The queue name to pop from
|
|
422
|
+
* @returns The acquired job, or null if queue is empty
|
|
423
|
+
*/
|
|
424
|
+
popFrom(queue: string): Promise<AcquiredJob | null>;
|
|
425
|
+
/**
|
|
426
|
+
* Recover stalled jobs that have been active for too long.
|
|
427
|
+
* A stalled job is one where the worker stopped responding (e.g., crash).
|
|
428
|
+
*
|
|
429
|
+
* Jobs within maxStalledCount are moved back to pending.
|
|
430
|
+
* Jobs exceeding maxStalledCount are failed permanently.
|
|
431
|
+
*
|
|
432
|
+
* @param queue - The queue to check for stalled jobs
|
|
433
|
+
* @param stalledThreshold - Duration in ms after which a job is considered stalled
|
|
434
|
+
* @param maxStalledCount - Maximum times a job can be recovered before failing
|
|
435
|
+
* @returns Number of jobs that were recovered (not including permanently failed ones)
|
|
436
|
+
*/
|
|
437
|
+
recoverStalledJobs(queue: string, stalledThreshold: number, maxStalledCount: number): Promise<number>;
|
|
438
|
+
/**
|
|
439
|
+
* Mark a job as completed and remove it from the queue.
|
|
440
|
+
*
|
|
441
|
+
* @param jobId - The job ID to complete
|
|
442
|
+
* @param queue - The queue the job belongs to
|
|
443
|
+
*/
|
|
444
|
+
completeJob(jobId: string, queue: string): Promise<void>;
|
|
445
|
+
/**
|
|
446
|
+
* Mark a job as failed permanently and remove it from the queue.
|
|
447
|
+
*
|
|
448
|
+
* @param jobId - The job ID to fail
|
|
449
|
+
* @param queue - The queue the job belongs to
|
|
450
|
+
* @param error - Optional error that caused the failure
|
|
451
|
+
*/
|
|
452
|
+
failJob(jobId: string, queue: string, error?: Error): Promise<void>;
|
|
453
|
+
/**
|
|
454
|
+
* Retry a job by moving it back to pending with incremented attempts.
|
|
455
|
+
*
|
|
456
|
+
* @param jobId - The job ID to retry
|
|
457
|
+
* @param queue - The queue the job belongs to
|
|
458
|
+
* @param retryAt - Optional future date to delay the retry
|
|
459
|
+
*/
|
|
460
|
+
retryJob(jobId: string, queue: string, retryAt?: Date): Promise<void>;
|
|
461
|
+
/**
|
|
462
|
+
* Push a job to the default queue for immediate processing.
|
|
463
|
+
*
|
|
464
|
+
* @param jobData - The job data to push
|
|
465
|
+
*/
|
|
466
|
+
push(jobData: JobData): Promise<void>;
|
|
467
|
+
/**
|
|
468
|
+
* Push a job to a specific queue for immediate processing.
|
|
469
|
+
*
|
|
470
|
+
* @param queue - The queue name to push to
|
|
471
|
+
* @param jobData - The job data to push
|
|
472
|
+
*/
|
|
473
|
+
pushOn(queue: string, jobData: JobData): Promise<void>;
|
|
474
|
+
/**
|
|
475
|
+
* Push a job to the default queue with a delay.
|
|
476
|
+
*
|
|
477
|
+
* @param jobData - The job data to push
|
|
478
|
+
* @param delay - Delay in milliseconds before the job becomes available
|
|
479
|
+
*/
|
|
480
|
+
pushLater(jobData: JobData, delay: number): Promise<void>;
|
|
481
|
+
/**
|
|
482
|
+
* Push a job to a specific queue with a delay.
|
|
483
|
+
*
|
|
484
|
+
* @param queue - The queue name to push to
|
|
485
|
+
* @param jobData - The job data to push
|
|
486
|
+
* @param delay - Delay in milliseconds before the job becomes available
|
|
487
|
+
*/
|
|
488
|
+
pushLaterOn(queue: string, jobData: JobData, delay: number): Promise<void>;
|
|
489
|
+
/**
|
|
490
|
+
* Get the number of pending jobs in the default queue.
|
|
491
|
+
*
|
|
492
|
+
* @returns The number of pending jobs
|
|
493
|
+
*/
|
|
494
|
+
size(): Promise<number>;
|
|
495
|
+
/**
|
|
496
|
+
* Get the number of pending jobs in a specific queue.
|
|
497
|
+
*
|
|
498
|
+
* @param queue - The queue name to check
|
|
499
|
+
* @returns The number of pending jobs
|
|
500
|
+
*/
|
|
501
|
+
sizeOf(queue: string): Promise<number>;
|
|
502
|
+
/**
|
|
503
|
+
* Clean up resources (close connections, etc.).
|
|
504
|
+
* Called when the worker stops or the adapter is no longer needed.
|
|
505
|
+
*/
|
|
506
|
+
destroy(): Promise<void>;
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
/**
|
|
510
|
+
* Fluent builder for dispatching jobs to the queue.
|
|
511
|
+
*
|
|
512
|
+
* Provides a chainable API for configuring job options before dispatch.
|
|
513
|
+
* Usually created via `Job.dispatch()` rather than directly.
|
|
514
|
+
*
|
|
515
|
+
* ```
|
|
516
|
+
* Job.dispatch(payload)
|
|
517
|
+
* .toQueue('emails') // optional: target queue
|
|
518
|
+
* .priority(1) // optional: 1-10, lower = higher priority
|
|
519
|
+
* .in('5m') // optional: delay before processing
|
|
520
|
+
* .with('redis') // optional: specific adapter
|
|
521
|
+
* .run() // dispatch the job
|
|
522
|
+
* ```
|
|
523
|
+
*
|
|
524
|
+
* @typeParam T - The payload type for this job
|
|
525
|
+
*
|
|
526
|
+
* @example
|
|
527
|
+
* ```typescript
|
|
528
|
+
* // Simple dispatch (auto-runs via thenable)
|
|
529
|
+
* await SendEmailJob.dispatch({ to: 'user@example.com', subject: 'Hello' })
|
|
530
|
+
*
|
|
531
|
+
* // With options
|
|
532
|
+
* const jobId = await SendEmailJob.dispatch({ to: 'user@example.com' })
|
|
533
|
+
* .toQueue('high-priority')
|
|
534
|
+
* .priority(1)
|
|
535
|
+
* .run()
|
|
536
|
+
*
|
|
537
|
+
* // Delayed job
|
|
538
|
+
* await ReminderJob.dispatch({ userId: 123 }).in('24h')
|
|
539
|
+
* ```
|
|
540
|
+
*/
|
|
541
|
+
declare class JobDispatcher<T> {
|
|
542
|
+
#private;
|
|
543
|
+
/**
|
|
544
|
+
* Create a new job dispatcher.
|
|
545
|
+
*
|
|
546
|
+
* @param name - The job class name (used to locate the class at runtime)
|
|
547
|
+
* @param payload - The data to pass to the job
|
|
548
|
+
*/
|
|
549
|
+
constructor(name: string, payload: T);
|
|
550
|
+
/**
|
|
551
|
+
* Set the target queue for this job.
|
|
552
|
+
*
|
|
553
|
+
* @param queue - Queue name (default: 'default')
|
|
554
|
+
* @returns This dispatcher for chaining
|
|
555
|
+
*
|
|
556
|
+
* @example
|
|
557
|
+
* ```typescript
|
|
558
|
+
* await SendEmailJob.dispatch(payload).toQueue('emails')
|
|
559
|
+
* ```
|
|
560
|
+
*/
|
|
561
|
+
toQueue(queue: string): this;
|
|
562
|
+
/**
|
|
563
|
+
* Delay the job execution.
|
|
564
|
+
*
|
|
565
|
+
* The job will be stored in a delayed state and moved to pending
|
|
566
|
+
* after the delay expires.
|
|
567
|
+
*
|
|
568
|
+
* @param delay - Delay as milliseconds or duration string ('5s', '1h', '7d')
|
|
569
|
+
* @returns This dispatcher for chaining
|
|
570
|
+
*
|
|
571
|
+
* @example
|
|
572
|
+
* ```typescript
|
|
573
|
+
* // Send reminder in 24 hours
|
|
574
|
+
* await ReminderJob.dispatch(payload).in('24h')
|
|
575
|
+
*
|
|
576
|
+
* // Process in 5 minutes
|
|
577
|
+
* await CleanupJob.dispatch(payload).in('5m')
|
|
578
|
+
* ```
|
|
579
|
+
*/
|
|
580
|
+
in(delay: Duration): this;
|
|
581
|
+
/**
|
|
582
|
+
* Set the job priority.
|
|
583
|
+
*
|
|
584
|
+
* Lower numbers = higher priority. Jobs with lower priority values
|
|
585
|
+
* are processed before jobs with higher values.
|
|
586
|
+
*
|
|
587
|
+
* @param priority - Priority level (1-10, default: 5)
|
|
588
|
+
* @returns This dispatcher for chaining
|
|
589
|
+
*
|
|
590
|
+
* @example
|
|
591
|
+
* ```typescript
|
|
592
|
+
* // High priority job
|
|
593
|
+
* await UrgentJob.dispatch(payload).priority(1)
|
|
594
|
+
*
|
|
595
|
+
* // Low priority job
|
|
596
|
+
* await BackgroundJob.dispatch(payload).priority(10)
|
|
597
|
+
* ```
|
|
598
|
+
*/
|
|
599
|
+
priority(priority: number): this;
|
|
600
|
+
/**
|
|
601
|
+
* Use a specific adapter for this job.
|
|
602
|
+
*
|
|
603
|
+
* @param adapter - Adapter name or factory function
|
|
604
|
+
* @returns This dispatcher for chaining
|
|
605
|
+
*
|
|
606
|
+
* @example
|
|
607
|
+
* ```typescript
|
|
608
|
+
* // Use named adapter
|
|
609
|
+
* await Job.dispatch(payload).with('redis')
|
|
610
|
+
*
|
|
611
|
+
* // Use custom adapter instance
|
|
612
|
+
* await Job.dispatch(payload).with(() => new CustomAdapter())
|
|
613
|
+
* ```
|
|
614
|
+
*/
|
|
615
|
+
with(adapter: string | (() => Adapter)): this;
|
|
616
|
+
/**
|
|
617
|
+
* Dispatch the job to the queue.
|
|
618
|
+
*
|
|
619
|
+
* @returns The unique job ID
|
|
620
|
+
*
|
|
621
|
+
* @example
|
|
622
|
+
* ```typescript
|
|
623
|
+
* const jobId = await SendEmailJob.dispatch(payload).run()
|
|
624
|
+
* console.log(`Dispatched job: ${jobId}`)
|
|
625
|
+
* ```
|
|
626
|
+
*/
|
|
627
|
+
run(): Promise<`${string}-${string}-${string}-${string}-${string}`>;
|
|
628
|
+
/**
|
|
629
|
+
* Thenable implementation for auto-dispatch when awaited.
|
|
630
|
+
*
|
|
631
|
+
* Allows `await Job.dispatch(payload)` without explicit `.run()`.
|
|
632
|
+
*
|
|
633
|
+
* @param onFulfilled - Success callback
|
|
634
|
+
* @param onRejected - Error callback
|
|
635
|
+
* @returns Promise resolving to the job ID
|
|
636
|
+
*/
|
|
637
|
+
then(onFulfilled?: (value: string) => any, onRejected?: (reason: any) => any): Promise<any>;
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
/**
|
|
641
|
+
* Abstract base class for all queue jobs.
|
|
642
|
+
*
|
|
643
|
+
* Extend this class to create your own jobs. Each job must implement
|
|
644
|
+
* the `execute()` method which contains the job's business logic.
|
|
645
|
+
*
|
|
646
|
+
* @typeParam Payload - The type of data this job receives
|
|
647
|
+
*
|
|
648
|
+
* @example
|
|
649
|
+
* ```typescript
|
|
650
|
+
* import { Job } from '@boringnode/queue'
|
|
651
|
+
* import type { JobContext } from '@boringnode/queue'
|
|
652
|
+
*
|
|
653
|
+
* interface SendEmailPayload {
|
|
654
|
+
* to: string
|
|
655
|
+
* subject: string
|
|
656
|
+
* body: string
|
|
657
|
+
* }
|
|
658
|
+
*
|
|
659
|
+
* export default class SendEmailJob extends Job<SendEmailPayload> {
|
|
660
|
+
* static options = {
|
|
661
|
+
* queue: 'emails',
|
|
662
|
+
* maxRetries: 3,
|
|
663
|
+
* }
|
|
664
|
+
*
|
|
665
|
+
* constructor(payload: SendEmailPayload, context: JobContext) {
|
|
666
|
+
* super(payload, context)
|
|
667
|
+
* }
|
|
668
|
+
*
|
|
669
|
+
* async execute() {
|
|
670
|
+
* console.log(`Attempt ${this.context.attempt} for job ${this.context.jobId}`)
|
|
671
|
+
* await sendEmail(this.payload.to, this.payload.subject, this.payload.body)
|
|
672
|
+
* }
|
|
673
|
+
*
|
|
674
|
+
* async failed(error: Error) {
|
|
675
|
+
* console.error(`Failed to send email to ${this.payload.to}:`, error)
|
|
676
|
+
* }
|
|
677
|
+
* }
|
|
678
|
+
* ```
|
|
679
|
+
*/
|
|
680
|
+
declare abstract class Job<Payload = any> {
|
|
681
|
+
#private;
|
|
682
|
+
/** Static options for this job class (queue, retries, timeout, etc.) */
|
|
683
|
+
static options: JobOptions;
|
|
684
|
+
/** The payload data passed to this job instance */
|
|
685
|
+
get payload(): Payload;
|
|
686
|
+
/**
|
|
687
|
+
* Context information for the current job execution.
|
|
688
|
+
*
|
|
689
|
+
* Provides metadata such as job ID, current attempt number,
|
|
690
|
+
* queue name, priority, and timing information.
|
|
691
|
+
*
|
|
692
|
+
* @example
|
|
693
|
+
* ```typescript
|
|
694
|
+
* async execute() {
|
|
695
|
+
* if (this.context.attempt > 1) {
|
|
696
|
+
* console.log(`Retry attempt ${this.context.attempt}`)
|
|
697
|
+
* }
|
|
698
|
+
* console.log(`Processing job ${this.context.jobId} on queue ${this.context.queue}`)
|
|
699
|
+
* }
|
|
700
|
+
* ```
|
|
701
|
+
*/
|
|
702
|
+
get context(): JobContext;
|
|
703
|
+
/**
|
|
704
|
+
* Create a new job instance.
|
|
705
|
+
*
|
|
706
|
+
* @param payload - The data to be processed by this job
|
|
707
|
+
* @param context - The job execution context (provided by the worker)
|
|
708
|
+
*/
|
|
709
|
+
constructor(payload: Payload, context: JobContext);
|
|
710
|
+
/**
|
|
711
|
+
* Dispatch this job to the queue.
|
|
712
|
+
*
|
|
713
|
+
* Returns a JobDispatcher for fluent configuration before dispatching.
|
|
714
|
+
* The job is not actually dispatched until `.run()` is called or the
|
|
715
|
+
* dispatcher is awaited.
|
|
716
|
+
*
|
|
717
|
+
* @param payload - The data to pass to the job
|
|
718
|
+
* @returns A JobDispatcher for fluent configuration
|
|
719
|
+
*
|
|
720
|
+
* @example
|
|
721
|
+
* ```typescript
|
|
722
|
+
* // Simple dispatch
|
|
723
|
+
* await SendEmailJob.dispatch({ to: 'user@example.com', subject: 'Hello' })
|
|
724
|
+
*
|
|
725
|
+
* // With options
|
|
726
|
+
* await SendEmailJob.dispatch({ to: 'user@example.com' })
|
|
727
|
+
* .toQueue('high-priority')
|
|
728
|
+
* .priority(1)
|
|
729
|
+
* .in('5m')
|
|
730
|
+
* .run()
|
|
731
|
+
* ```
|
|
732
|
+
*/
|
|
733
|
+
static dispatch<T extends Job>(this: new (payload: any, context: JobContext) => T, payload: T extends Job<infer P> ? P : never): JobDispatcher<T extends Job<infer P> ? P : never>;
|
|
734
|
+
/**
|
|
735
|
+
* Execute the job's business logic.
|
|
736
|
+
*
|
|
737
|
+
* This method is called by the worker when processing the job.
|
|
738
|
+
* Implement your job's logic here.
|
|
739
|
+
*
|
|
740
|
+
* @param signal - Optional AbortSignal for timeout handling.
|
|
741
|
+
* Check `signal.aborted` for long-running operations.
|
|
742
|
+
* @throws Any error thrown will trigger retry logic (if configured)
|
|
743
|
+
*
|
|
744
|
+
* @example
|
|
745
|
+
* ```typescript
|
|
746
|
+
* async execute(signal?: AbortSignal) {
|
|
747
|
+
* for (const item of this.payload.items) {
|
|
748
|
+
* if (signal?.aborted) {
|
|
749
|
+
* throw new Error('Job timed out')
|
|
750
|
+
* }
|
|
751
|
+
* await processItem(item)
|
|
752
|
+
* }
|
|
753
|
+
* }
|
|
754
|
+
* ```
|
|
755
|
+
*/
|
|
756
|
+
abstract execute(signal?: AbortSignal): Promise<void>;
|
|
757
|
+
/**
|
|
758
|
+
* Called when the job has permanently failed (after all retries exhausted).
|
|
759
|
+
*
|
|
760
|
+
* Use this hook for cleanup, logging, or notifications.
|
|
761
|
+
* This is optional - implement only if you need failure handling.
|
|
762
|
+
*
|
|
763
|
+
* @param error - The error that caused the final failure
|
|
764
|
+
*
|
|
765
|
+
* @example
|
|
766
|
+
* ```typescript
|
|
767
|
+
* async failed(error: Error) {
|
|
768
|
+
* await notifyAdmin(`Job failed: ${error.message}`)
|
|
769
|
+
* await cleanup(this.payload)
|
|
770
|
+
* }
|
|
771
|
+
* ```
|
|
772
|
+
*/
|
|
773
|
+
failed?(error: Error): Promise<void>;
|
|
774
|
+
}
|
|
775
|
+
|
|
776
|
+
export { type Adapter as A, type BackoffStrategy as B, type Duration as D, type JobData as J, type Logger as L, type QueueManagerConfig as Q, type RetryConfig as R, type WorkerCycle as W, type AcquiredJob as a, type JobFactory as b, Job as c, type JobClass as d, customBackoff as e, exponentialBackoff as f, fixedBackoff as g, type JobOptions as h, type JobContext as i, type BackoffConfig as j, type QueueConfig as k, linearBackoff as l, type WorkerConfig as m, type AdapterFactory as n };
|