@riktajs/queue 0.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/README.md +476 -0
- package/dist/config/queue.config.d.ts +137 -0
- package/dist/config/queue.config.d.ts.map +1 -0
- package/dist/config/queue.config.js +82 -0
- package/dist/config/queue.config.js.map +1 -0
- package/dist/constants.d.ts +33 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +37 -0
- package/dist/constants.js.map +1 -0
- package/dist/decorators/events.decorator.d.ts +85 -0
- package/dist/decorators/events.decorator.d.ts.map +1 -0
- package/dist/decorators/events.decorator.js +120 -0
- package/dist/decorators/events.decorator.js.map +1 -0
- package/dist/decorators/index.d.ts +8 -0
- package/dist/decorators/index.d.ts.map +1 -0
- package/dist/decorators/index.js +8 -0
- package/dist/decorators/index.js.map +1 -0
- package/dist/decorators/process.decorator.d.ts +41 -0
- package/dist/decorators/process.decorator.d.ts.map +1 -0
- package/dist/decorators/process.decorator.js +61 -0
- package/dist/decorators/process.decorator.js.map +1 -0
- package/dist/decorators/processor.decorator.d.ts +41 -0
- package/dist/decorators/processor.decorator.d.ts.map +1 -0
- package/dist/decorators/processor.decorator.js +59 -0
- package/dist/decorators/processor.decorator.js.map +1 -0
- package/dist/decorators/queue.decorator.d.ts +35 -0
- package/dist/decorators/queue.decorator.d.ts.map +1 -0
- package/dist/decorators/queue.decorator.js +49 -0
- package/dist/decorators/queue.decorator.js.map +1 -0
- package/dist/events/queue-events.d.ts +32 -0
- package/dist/events/queue-events.d.ts.map +1 -0
- package/dist/events/queue-events.js +103 -0
- package/dist/events/queue-events.js.map +1 -0
- package/dist/index.d.ts +22 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +30 -0
- package/dist/index.js.map +1 -0
- package/dist/monitoring/bull-board.d.ts +77 -0
- package/dist/monitoring/bull-board.d.ts.map +1 -0
- package/dist/monitoring/bull-board.js +112 -0
- package/dist/monitoring/bull-board.js.map +1 -0
- package/dist/providers/queue.provider.d.ts +94 -0
- package/dist/providers/queue.provider.d.ts.map +1 -0
- package/dist/providers/queue.provider.js +333 -0
- package/dist/providers/queue.provider.js.map +1 -0
- package/dist/services/queue.service.d.ts +133 -0
- package/dist/services/queue.service.d.ts.map +1 -0
- package/dist/services/queue.service.js +192 -0
- package/dist/services/queue.service.js.map +1 -0
- package/dist/types.d.ts +133 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +5 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/connection.d.ts +47 -0
- package/dist/utils/connection.d.ts.map +1 -0
- package/dist/utils/connection.js +104 -0
- package/dist/utils/connection.js.map +1 -0
- package/dist/utils/validation.d.ts +187 -0
- package/dist/utils/validation.d.ts.map +1 -0
- package/dist/utils/validation.js +156 -0
- package/dist/utils/validation.js.map +1 -0
- package/package.json +69 -0
|
@@ -0,0 +1,333 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* QueueProvider - Main provider for queue lifecycle management
|
|
3
|
+
*
|
|
4
|
+
* Implements OnProviderInit and OnProviderDestroy for Rikta lifecycle integration.
|
|
5
|
+
* Not @Injectable - use createQueueProvider() factory function.
|
|
6
|
+
*/
|
|
7
|
+
import { Queue, Worker, QueueEvents } from 'bullmq';
|
|
8
|
+
import { QUEUE_PROVIDER, QUEUE_SERVICE, getQueueToken, getWorkerToken } from '../constants.js';
|
|
9
|
+
import { loadQueueConfig } from '../config/queue.config.js';
|
|
10
|
+
import { RedisConnectionManager, QueueConnectionError } from '../utils/connection.js';
|
|
11
|
+
import { getProcessorOptions, isProcessor } from '../decorators/processor.decorator.js';
|
|
12
|
+
import { getJobHandlers } from '../decorators/process.decorator.js';
|
|
13
|
+
import { getEventHandlers } from '../decorators/events.decorator.js';
|
|
14
|
+
import { publishQueueEvent } from '../events/queue-events.js';
|
|
15
|
+
import { QueueService } from '../services/queue.service.js';
|
|
16
|
+
/**
|
|
17
|
+
* QueueProvider manages the lifecycle of all queues and workers.
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* ```typescript
|
|
21
|
+
* const provider = createQueueProvider({
|
|
22
|
+
* config: { redis: { host: 'localhost', port: 6379 } }
|
|
23
|
+
* });
|
|
24
|
+
*
|
|
25
|
+
* // In Rikta bootstrap:
|
|
26
|
+
* await app.register(provider);
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
export class QueueProvider {
|
|
30
|
+
connectionManager = new RedisConnectionManager();
|
|
31
|
+
config;
|
|
32
|
+
queues = new Map();
|
|
33
|
+
workers = new Map();
|
|
34
|
+
processorClasses = [];
|
|
35
|
+
initialized = false;
|
|
36
|
+
eventBus = null;
|
|
37
|
+
options = {
|
|
38
|
+
autoInitialize: true,
|
|
39
|
+
retryAttempts: 0,
|
|
40
|
+
retryDelay: 3000,
|
|
41
|
+
};
|
|
42
|
+
/**
|
|
43
|
+
* Configure the provider with options
|
|
44
|
+
*/
|
|
45
|
+
configure(options) {
|
|
46
|
+
this.options = { ...this.options, ...options };
|
|
47
|
+
return this;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Register processor classes for auto-discovery
|
|
51
|
+
*/
|
|
52
|
+
registerProcessors(...processors) {
|
|
53
|
+
this.processorClasses.push(...processors);
|
|
54
|
+
return this;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Set EventBus for event emission (optional)
|
|
58
|
+
*/
|
|
59
|
+
setEventBus(eventBus) {
|
|
60
|
+
this.eventBus = eventBus;
|
|
61
|
+
return this;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Initialize all queues and workers (called by Rikta lifecycle)
|
|
65
|
+
*/
|
|
66
|
+
async onProviderInit() {
|
|
67
|
+
console.log('🚀 Queue: Initializing queue system...');
|
|
68
|
+
try {
|
|
69
|
+
// Load configuration
|
|
70
|
+
this.config = loadQueueConfig(this.options.config);
|
|
71
|
+
// Configure Redis connection
|
|
72
|
+
this.connectionManager.configure(this.config.redis);
|
|
73
|
+
// Test connection
|
|
74
|
+
await this.testConnection();
|
|
75
|
+
// Discover and register processors
|
|
76
|
+
await this.discoverAndRegisterProcessors();
|
|
77
|
+
// Register in container
|
|
78
|
+
this.registerInContainer();
|
|
79
|
+
this.initialized = true;
|
|
80
|
+
console.log(`✅ Queue: Initialized ${this.queues.size} queue(s), ${this.workers.size} worker(s)`);
|
|
81
|
+
}
|
|
82
|
+
catch (error) {
|
|
83
|
+
console.error('❌ Queue: Failed to initialize queue system');
|
|
84
|
+
throw error;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Gracefully shutdown all workers and close connections
|
|
89
|
+
*/
|
|
90
|
+
async onProviderDestroy() {
|
|
91
|
+
if (!this.initialized)
|
|
92
|
+
return;
|
|
93
|
+
console.log('🔌 Queue: Shutting down queue system...');
|
|
94
|
+
try {
|
|
95
|
+
const timeout = this.config.shutdownTimeout || 30000;
|
|
96
|
+
// Close all workers gracefully
|
|
97
|
+
const workerClosePromises = Array.from(this.workers.values()).map(async ({ worker, queueName }) => {
|
|
98
|
+
console.log(` ⏳ Closing worker for ${queueName}...`);
|
|
99
|
+
await Promise.race([
|
|
100
|
+
worker.close(),
|
|
101
|
+
this.delay(timeout),
|
|
102
|
+
]);
|
|
103
|
+
});
|
|
104
|
+
await Promise.all(workerClosePromises);
|
|
105
|
+
// Close all queue event listeners
|
|
106
|
+
for (const { queueEvents } of this.queues.values()) {
|
|
107
|
+
if (queueEvents) {
|
|
108
|
+
await queueEvents.close();
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
// Close all queues
|
|
112
|
+
for (const { queue } of this.queues.values()) {
|
|
113
|
+
await queue.close();
|
|
114
|
+
}
|
|
115
|
+
// Close Redis connection
|
|
116
|
+
await this.connectionManager.close();
|
|
117
|
+
this.initialized = false;
|
|
118
|
+
console.log('✅ Queue: Queue system shut down');
|
|
119
|
+
}
|
|
120
|
+
catch (error) {
|
|
121
|
+
console.error('❌ Queue: Error during shutdown:', error);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Get a queue by name
|
|
126
|
+
*/
|
|
127
|
+
getQueue(name) {
|
|
128
|
+
return this.queues.get(name)?.queue;
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Get all registered queues
|
|
132
|
+
*/
|
|
133
|
+
getAllQueues() {
|
|
134
|
+
return Array.from(this.queues.values()).map(q => q.queue);
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Check if the provider is initialized
|
|
138
|
+
*/
|
|
139
|
+
isInitialized() {
|
|
140
|
+
return this.initialized;
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Get configuration
|
|
144
|
+
*/
|
|
145
|
+
getConfig() {
|
|
146
|
+
return this.config;
|
|
147
|
+
}
|
|
148
|
+
// --- Private methods ---
|
|
149
|
+
async testConnection() {
|
|
150
|
+
const client = this.connectionManager.getClient();
|
|
151
|
+
const { retryAttempts = 0, retryDelay = 3000 } = this.options;
|
|
152
|
+
let lastError;
|
|
153
|
+
for (let attempt = 0; attempt <= retryAttempts; attempt++) {
|
|
154
|
+
try {
|
|
155
|
+
await client.ping();
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
catch (error) {
|
|
159
|
+
lastError = error;
|
|
160
|
+
if (attempt < retryAttempts) {
|
|
161
|
+
console.warn(`⚠️ Queue: Connection attempt ${attempt + 1}/${retryAttempts + 1} failed. Retrying in ${retryDelay}ms...`);
|
|
162
|
+
await this.delay(retryDelay);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
throw new QueueConnectionError(`Failed to connect to Redis: ${lastError?.message}`, this.config.redis.host, this.config.redis.port, lastError);
|
|
167
|
+
}
|
|
168
|
+
async discoverAndRegisterProcessors() {
|
|
169
|
+
for (const processorClass of this.processorClasses) {
|
|
170
|
+
if (!isProcessor(processorClass)) {
|
|
171
|
+
console.warn(`⚠️ Queue: ${processorClass.name} is not decorated with @Processor, skipping`);
|
|
172
|
+
continue;
|
|
173
|
+
}
|
|
174
|
+
const options = getProcessorOptions(processorClass);
|
|
175
|
+
if (!options)
|
|
176
|
+
continue;
|
|
177
|
+
await this.registerProcessor(processorClass, options);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
async registerProcessor(processorClass, options) {
|
|
181
|
+
const { queueName, concurrency, rateLimiter, workerOptions } = options;
|
|
182
|
+
// Create queue if not exists
|
|
183
|
+
if (!this.queues.has(queueName)) {
|
|
184
|
+
await this.createQueue(queueName);
|
|
185
|
+
}
|
|
186
|
+
// Get job handlers
|
|
187
|
+
const jobHandlers = getJobHandlers(processorClass);
|
|
188
|
+
const eventHandlers = getEventHandlers(processorClass);
|
|
189
|
+
// Create processor instance
|
|
190
|
+
const processor = new processorClass();
|
|
191
|
+
// Create worker
|
|
192
|
+
const worker = new Worker(queueName, async (job) => {
|
|
193
|
+
// Find handler for this job
|
|
194
|
+
const handler = jobHandlers.find(h => h.name === job.name);
|
|
195
|
+
if (!handler) {
|
|
196
|
+
throw new Error(`No handler found for job: ${job.name}`);
|
|
197
|
+
}
|
|
198
|
+
// Call handler method
|
|
199
|
+
const method = processor[handler.methodName];
|
|
200
|
+
if (typeof method !== 'function') {
|
|
201
|
+
throw new Error(`Handler method ${handler.methodName} not found`);
|
|
202
|
+
}
|
|
203
|
+
return method.call(processor, job);
|
|
204
|
+
}, {
|
|
205
|
+
connection: this.connectionManager.getClient(),
|
|
206
|
+
concurrency: concurrency || this.config.defaultConcurrency || 1,
|
|
207
|
+
limiter: rateLimiter || this.config.defaultRateLimiter,
|
|
208
|
+
...workerOptions,
|
|
209
|
+
});
|
|
210
|
+
// Attach event handlers
|
|
211
|
+
this.attachWorkerEvents(worker, queueName, processor, eventHandlers);
|
|
212
|
+
// Store worker
|
|
213
|
+
this.workers.set(queueName, {
|
|
214
|
+
queueName,
|
|
215
|
+
worker,
|
|
216
|
+
processor,
|
|
217
|
+
processorClass,
|
|
218
|
+
});
|
|
219
|
+
console.log(` 📦 Registered processor for queue: ${queueName} (${jobHandlers.length} handlers)`);
|
|
220
|
+
}
|
|
221
|
+
async createQueue(name) {
|
|
222
|
+
const queue = new Queue(name, {
|
|
223
|
+
connection: this.connectionManager.getClient(),
|
|
224
|
+
});
|
|
225
|
+
// Create queue events for monitoring
|
|
226
|
+
const queueEvents = new QueueEvents(name, {
|
|
227
|
+
connection: this.connectionManager.getClient(),
|
|
228
|
+
});
|
|
229
|
+
this.queues.set(name, { name, queue, queueEvents });
|
|
230
|
+
}
|
|
231
|
+
attachWorkerEvents(worker, queueName, processor, eventHandlers) {
|
|
232
|
+
worker.on('completed', async (job, result) => {
|
|
233
|
+
await this.handleEvent('job:completed', queueName, processor, eventHandlers, job, result);
|
|
234
|
+
});
|
|
235
|
+
worker.on('failed', async (job, error) => {
|
|
236
|
+
await this.handleEvent('job:failed', queueName, processor, eventHandlers, job, error);
|
|
237
|
+
});
|
|
238
|
+
worker.on('progress', async (job, progress) => {
|
|
239
|
+
await this.handleEvent('job:progress', queueName, processor, eventHandlers, job, progress);
|
|
240
|
+
});
|
|
241
|
+
worker.on('stalled', async (jobId) => {
|
|
242
|
+
await this.handleEvent('job:stalled', queueName, processor, eventHandlers, jobId);
|
|
243
|
+
});
|
|
244
|
+
worker.on('ready', async () => {
|
|
245
|
+
await this.handleEvent('worker:ready', queueName, processor, eventHandlers);
|
|
246
|
+
});
|
|
247
|
+
worker.on('error', async (error) => {
|
|
248
|
+
await this.handleEvent('worker:error', queueName, processor, eventHandlers, error);
|
|
249
|
+
});
|
|
250
|
+
}
|
|
251
|
+
async handleEvent(event, queueName, processor, eventHandlers, ...args) {
|
|
252
|
+
// Call processor event handlers
|
|
253
|
+
const handlers = eventHandlers.filter(h => h.event === event);
|
|
254
|
+
for (const handler of handlers) {
|
|
255
|
+
const method = processor[handler.methodName];
|
|
256
|
+
if (typeof method === 'function') {
|
|
257
|
+
try {
|
|
258
|
+
await method.call(processor, ...args);
|
|
259
|
+
}
|
|
260
|
+
catch (error) {
|
|
261
|
+
console.error(`Error in event handler ${handler.methodName}:`, error);
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
// Emit to EventBus if available
|
|
266
|
+
if (this.eventBus) {
|
|
267
|
+
try {
|
|
268
|
+
await publishQueueEvent(this.eventBus, event, queueName, ...args);
|
|
269
|
+
}
|
|
270
|
+
catch {
|
|
271
|
+
// Ignore EventBus errors
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
registerInContainer() {
|
|
276
|
+
try {
|
|
277
|
+
// Dynamic import to avoid circular dependency
|
|
278
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
279
|
+
const { Container } = require('@riktajs/core');
|
|
280
|
+
const container = Container.getInstance();
|
|
281
|
+
// Register provider
|
|
282
|
+
container.registerValue(QUEUE_PROVIDER, this);
|
|
283
|
+
// Register queues
|
|
284
|
+
for (const [name, { queue }] of this.queues) {
|
|
285
|
+
container.registerValue(getQueueToken(name), queue);
|
|
286
|
+
}
|
|
287
|
+
// Register workers
|
|
288
|
+
for (const [name, { worker }] of this.workers) {
|
|
289
|
+
container.registerValue(getWorkerToken(name), worker);
|
|
290
|
+
}
|
|
291
|
+
// Create and register QueueService
|
|
292
|
+
const queueService = new QueueService(this);
|
|
293
|
+
container.registerValue(QUEUE_SERVICE, queueService);
|
|
294
|
+
}
|
|
295
|
+
catch {
|
|
296
|
+
// Container not available, skip registration
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
delay(ms) {
|
|
300
|
+
return new Promise(resolve => setTimeout(resolve, ms));
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
/**
|
|
304
|
+
* Factory function to create a QueueProvider
|
|
305
|
+
*/
|
|
306
|
+
export function createQueueProvider(options) {
|
|
307
|
+
const provider = new QueueProvider();
|
|
308
|
+
if (options) {
|
|
309
|
+
provider.configure(options);
|
|
310
|
+
}
|
|
311
|
+
return provider;
|
|
312
|
+
}
|
|
313
|
+
/**
|
|
314
|
+
* Error thrown when queue initialization fails
|
|
315
|
+
*/
|
|
316
|
+
export class QueueInitializationError extends Error {
|
|
317
|
+
cause;
|
|
318
|
+
constructor(message, cause) {
|
|
319
|
+
super(message);
|
|
320
|
+
this.cause = cause;
|
|
321
|
+
this.name = 'QueueInitializationError';
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
/**
|
|
325
|
+
* Error thrown when a duplicate queue is detected
|
|
326
|
+
*/
|
|
327
|
+
export class DuplicateQueueError extends Error {
|
|
328
|
+
constructor(queueName) {
|
|
329
|
+
super(`Duplicate queue registration: ${queueName}`);
|
|
330
|
+
this.name = 'DuplicateQueueError';
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
//# sourceMappingURL=queue.provider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"queue.provider.js","sourceRoot":"","sources":["../../src/providers/queue.provider.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* QueueService - Injectable service for adding jobs to queues
|
|
3
|
+
*/
|
|
4
|
+
import type { Job, JobsOptions, RepeatOptions } from 'bullmq';
|
|
5
|
+
import type { QueueProvider } from '../providers/queue.provider.js';
|
|
6
|
+
import type { AddJobOptions, ScheduleOptions } from '../types.js';
|
|
7
|
+
/**
|
|
8
|
+
* Service for adding jobs to queues from anywhere in the application.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```typescript
|
|
12
|
+
* @Injectable()
|
|
13
|
+
* class NotificationService {
|
|
14
|
+
* @Autowired()
|
|
15
|
+
* private queueService!: QueueService;
|
|
16
|
+
*
|
|
17
|
+
* async sendNotification(userId: string, message: string) {
|
|
18
|
+
* await this.queueService.addJob('notifications', 'send', {
|
|
19
|
+
* userId,
|
|
20
|
+
* message,
|
|
21
|
+
* });
|
|
22
|
+
* }
|
|
23
|
+
* }
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
export declare class QueueService {
|
|
27
|
+
private readonly provider;
|
|
28
|
+
constructor(provider: QueueProvider);
|
|
29
|
+
/**
|
|
30
|
+
* Add a job to a queue
|
|
31
|
+
*
|
|
32
|
+
* @param queueName - Name of the queue
|
|
33
|
+
* @param jobName - Name of the job (matches @Process decorator)
|
|
34
|
+
* @param data - Job payload data
|
|
35
|
+
* @param options - Optional job options
|
|
36
|
+
* @returns The created job
|
|
37
|
+
*/
|
|
38
|
+
addJob<TData = unknown, TResult = unknown>(queueName: string, jobName: string, data: TData, options?: AddJobOptions): Promise<Job<TData, TResult>>;
|
|
39
|
+
/**
|
|
40
|
+
* Add multiple jobs to a queue in bulk
|
|
41
|
+
*
|
|
42
|
+
* @param queueName - Name of the queue
|
|
43
|
+
* @param jobs - Array of jobs to add
|
|
44
|
+
* @returns Array of created jobs
|
|
45
|
+
*/
|
|
46
|
+
addJobs<TData = unknown, TResult = unknown>(queueName: string, jobs: Array<{
|
|
47
|
+
name: string;
|
|
48
|
+
data: TData;
|
|
49
|
+
options?: JobsOptions;
|
|
50
|
+
}>): Promise<Job<TData, TResult>[]>;
|
|
51
|
+
/**
|
|
52
|
+
* Add a delayed job
|
|
53
|
+
*
|
|
54
|
+
* @param queueName - Name of the queue
|
|
55
|
+
* @param jobName - Name of the job
|
|
56
|
+
* @param data - Job payload data
|
|
57
|
+
* @param delay - Delay in milliseconds
|
|
58
|
+
* @param options - Optional job options
|
|
59
|
+
*/
|
|
60
|
+
addDelayedJob<TData = unknown, TResult = unknown>(queueName: string, jobName: string, data: TData, delay: number, options?: JobsOptions): Promise<Job<TData, TResult>>;
|
|
61
|
+
/**
|
|
62
|
+
* Add a repeatable job (scheduled)
|
|
63
|
+
*
|
|
64
|
+
* @param queueName - Name of the queue
|
|
65
|
+
* @param jobName - Name of the job
|
|
66
|
+
* @param data - Job payload data
|
|
67
|
+
* @param repeat - Repeat options (cron pattern, interval, etc.)
|
|
68
|
+
* @param options - Optional schedule options
|
|
69
|
+
*/
|
|
70
|
+
addRepeatableJob<TData = unknown, TResult = unknown>(queueName: string, jobName: string, data: TData, repeat: RepeatOptions, options?: ScheduleOptions): Promise<Job<TData, TResult>>;
|
|
71
|
+
/**
|
|
72
|
+
* Remove a repeatable job
|
|
73
|
+
*
|
|
74
|
+
* @param queueName - Name of the queue
|
|
75
|
+
* @param jobName - Name of the job
|
|
76
|
+
* @param repeat - The repeat options used when creating the job
|
|
77
|
+
*/
|
|
78
|
+
removeRepeatableJob(queueName: string, jobName: string, repeat: RepeatOptions): Promise<boolean>;
|
|
79
|
+
/**
|
|
80
|
+
* Get a job by ID
|
|
81
|
+
*
|
|
82
|
+
* @param queueName - Name of the queue
|
|
83
|
+
* @param jobId - Job ID
|
|
84
|
+
*/
|
|
85
|
+
getJob<TData = unknown, TResult = unknown>(queueName: string, jobId: string): Promise<Job<TData, TResult> | undefined>;
|
|
86
|
+
/**
|
|
87
|
+
* Get queue statistics
|
|
88
|
+
*
|
|
89
|
+
* @param queueName - Name of the queue
|
|
90
|
+
*/
|
|
91
|
+
getQueueStats(queueName: string): Promise<{
|
|
92
|
+
waiting: number;
|
|
93
|
+
active: number;
|
|
94
|
+
completed: number;
|
|
95
|
+
failed: number;
|
|
96
|
+
delayed: number;
|
|
97
|
+
paused: number;
|
|
98
|
+
}>;
|
|
99
|
+
/**
|
|
100
|
+
* Pause a queue
|
|
101
|
+
*/
|
|
102
|
+
pauseQueue(queueName: string): Promise<void>;
|
|
103
|
+
/**
|
|
104
|
+
* Resume a queue
|
|
105
|
+
*/
|
|
106
|
+
resumeQueue(queueName: string): Promise<void>;
|
|
107
|
+
/**
|
|
108
|
+
* Clear all jobs from a queue
|
|
109
|
+
*
|
|
110
|
+
* @param queueName - Name of the queue
|
|
111
|
+
* @param status - Which jobs to clear (default: all)
|
|
112
|
+
*/
|
|
113
|
+
clearQueue(queueName: string, status?: 'completed' | 'failed' | 'delayed' | 'wait' | 'active'): Promise<void>;
|
|
114
|
+
/**
|
|
115
|
+
* Get all queue names
|
|
116
|
+
*/
|
|
117
|
+
getQueueNames(): string[];
|
|
118
|
+
private getQueueOrThrow;
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Error thrown when a queue is not found
|
|
122
|
+
*/
|
|
123
|
+
export declare class QueueNotFoundError extends Error {
|
|
124
|
+
constructor(queueName: string);
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Error thrown when job validation fails
|
|
128
|
+
*/
|
|
129
|
+
export declare class JobValidationError extends Error {
|
|
130
|
+
readonly errors: unknown[];
|
|
131
|
+
constructor(message: string, errors: unknown[]);
|
|
132
|
+
}
|
|
133
|
+
//# sourceMappingURL=queue.service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"queue.service.d.ts","sourceRoot":"","sources":["../../src/services/queue.service.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* QueueService - Injectable service for adding jobs to queues
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Service for adding jobs to queues from anywhere in the application.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```typescript
|
|
9
|
+
* @Injectable()
|
|
10
|
+
* class NotificationService {
|
|
11
|
+
* @Autowired()
|
|
12
|
+
* private queueService!: QueueService;
|
|
13
|
+
*
|
|
14
|
+
* async sendNotification(userId: string, message: string) {
|
|
15
|
+
* await this.queueService.addJob('notifications', 'send', {
|
|
16
|
+
* userId,
|
|
17
|
+
* message,
|
|
18
|
+
* });
|
|
19
|
+
* }
|
|
20
|
+
* }
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
export class QueueService {
|
|
24
|
+
provider;
|
|
25
|
+
constructor(provider) {
|
|
26
|
+
this.provider = provider;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Add a job to a queue
|
|
30
|
+
*
|
|
31
|
+
* @param queueName - Name of the queue
|
|
32
|
+
* @param jobName - Name of the job (matches @Process decorator)
|
|
33
|
+
* @param data - Job payload data
|
|
34
|
+
* @param options - Optional job options
|
|
35
|
+
* @returns The created job
|
|
36
|
+
*/
|
|
37
|
+
async addJob(queueName, jobName, data, options) {
|
|
38
|
+
const queue = this.getQueueOrThrow(queueName);
|
|
39
|
+
// Handle deduplication
|
|
40
|
+
const jobOptions = { ...options };
|
|
41
|
+
if (options?.deduplicationKey) {
|
|
42
|
+
jobOptions.jobId = options.deduplicationKey;
|
|
43
|
+
}
|
|
44
|
+
return queue.add(jobName, data, jobOptions);
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Add multiple jobs to a queue in bulk
|
|
48
|
+
*
|
|
49
|
+
* @param queueName - Name of the queue
|
|
50
|
+
* @param jobs - Array of jobs to add
|
|
51
|
+
* @returns Array of created jobs
|
|
52
|
+
*/
|
|
53
|
+
async addJobs(queueName, jobs) {
|
|
54
|
+
const queue = this.getQueueOrThrow(queueName);
|
|
55
|
+
const bulkJobs = jobs.map(j => ({
|
|
56
|
+
name: j.name,
|
|
57
|
+
data: j.data,
|
|
58
|
+
opts: j.options,
|
|
59
|
+
}));
|
|
60
|
+
return queue.addBulk(bulkJobs);
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Add a delayed job
|
|
64
|
+
*
|
|
65
|
+
* @param queueName - Name of the queue
|
|
66
|
+
* @param jobName - Name of the job
|
|
67
|
+
* @param data - Job payload data
|
|
68
|
+
* @param delay - Delay in milliseconds
|
|
69
|
+
* @param options - Optional job options
|
|
70
|
+
*/
|
|
71
|
+
async addDelayedJob(queueName, jobName, data, delay, options) {
|
|
72
|
+
return this.addJob(queueName, jobName, data, { ...options, delay });
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Add a repeatable job (scheduled)
|
|
76
|
+
*
|
|
77
|
+
* @param queueName - Name of the queue
|
|
78
|
+
* @param jobName - Name of the job
|
|
79
|
+
* @param data - Job payload data
|
|
80
|
+
* @param repeat - Repeat options (cron pattern, interval, etc.)
|
|
81
|
+
* @param options - Optional schedule options
|
|
82
|
+
*/
|
|
83
|
+
async addRepeatableJob(queueName, jobName, data, repeat, options) {
|
|
84
|
+
const queue = this.getQueueOrThrow(queueName);
|
|
85
|
+
return queue.add(jobName, data, {
|
|
86
|
+
...options,
|
|
87
|
+
repeat,
|
|
88
|
+
jobId: options?.jobId,
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Remove a repeatable job
|
|
93
|
+
*
|
|
94
|
+
* @param queueName - Name of the queue
|
|
95
|
+
* @param jobName - Name of the job
|
|
96
|
+
* @param repeat - The repeat options used when creating the job
|
|
97
|
+
*/
|
|
98
|
+
async removeRepeatableJob(queueName, jobName, repeat) {
|
|
99
|
+
const queue = this.getQueueOrThrow(queueName);
|
|
100
|
+
return queue.removeRepeatableByKey(`${jobName}:${JSON.stringify(repeat)}`);
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Get a job by ID
|
|
104
|
+
*
|
|
105
|
+
* @param queueName - Name of the queue
|
|
106
|
+
* @param jobId - Job ID
|
|
107
|
+
*/
|
|
108
|
+
async getJob(queueName, jobId) {
|
|
109
|
+
const queue = this.getQueueOrThrow(queueName);
|
|
110
|
+
return queue.getJob(jobId);
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Get queue statistics
|
|
114
|
+
*
|
|
115
|
+
* @param queueName - Name of the queue
|
|
116
|
+
*/
|
|
117
|
+
async getQueueStats(queueName) {
|
|
118
|
+
const queue = this.getQueueOrThrow(queueName);
|
|
119
|
+
const [waiting, active, completed, failed, delayed, paused] = await Promise.all([
|
|
120
|
+
queue.getWaitingCount(),
|
|
121
|
+
queue.getActiveCount(),
|
|
122
|
+
queue.getCompletedCount(),
|
|
123
|
+
queue.getFailedCount(),
|
|
124
|
+
queue.getDelayedCount(),
|
|
125
|
+
queue.isPaused().then(p => (p ? 1 : 0)),
|
|
126
|
+
]);
|
|
127
|
+
return { waiting, active, completed, failed, delayed, paused };
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Pause a queue
|
|
131
|
+
*/
|
|
132
|
+
async pauseQueue(queueName) {
|
|
133
|
+
const queue = this.getQueueOrThrow(queueName);
|
|
134
|
+
await queue.pause();
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Resume a queue
|
|
138
|
+
*/
|
|
139
|
+
async resumeQueue(queueName) {
|
|
140
|
+
const queue = this.getQueueOrThrow(queueName);
|
|
141
|
+
await queue.resume();
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Clear all jobs from a queue
|
|
145
|
+
*
|
|
146
|
+
* @param queueName - Name of the queue
|
|
147
|
+
* @param status - Which jobs to clear (default: all)
|
|
148
|
+
*/
|
|
149
|
+
async clearQueue(queueName, status) {
|
|
150
|
+
const queue = this.getQueueOrThrow(queueName);
|
|
151
|
+
if (status) {
|
|
152
|
+
await queue.clean(0, 0, status);
|
|
153
|
+
}
|
|
154
|
+
else {
|
|
155
|
+
await queue.obliterate({ force: true });
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Get all queue names
|
|
160
|
+
*/
|
|
161
|
+
getQueueNames() {
|
|
162
|
+
return this.provider.getAllQueues().map(q => q.name);
|
|
163
|
+
}
|
|
164
|
+
getQueueOrThrow(queueName) {
|
|
165
|
+
const queue = this.provider.getQueue(queueName);
|
|
166
|
+
if (!queue) {
|
|
167
|
+
throw new QueueNotFoundError(queueName);
|
|
168
|
+
}
|
|
169
|
+
return queue;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Error thrown when a queue is not found
|
|
174
|
+
*/
|
|
175
|
+
export class QueueNotFoundError extends Error {
|
|
176
|
+
constructor(queueName) {
|
|
177
|
+
super(`Queue not found: ${queueName}`);
|
|
178
|
+
this.name = 'QueueNotFoundError';
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Error thrown when job validation fails
|
|
183
|
+
*/
|
|
184
|
+
export class JobValidationError extends Error {
|
|
185
|
+
errors;
|
|
186
|
+
constructor(message, errors) {
|
|
187
|
+
super(message);
|
|
188
|
+
this.errors = errors;
|
|
189
|
+
this.name = 'JobValidationError';
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
//# sourceMappingURL=queue.service.js.map
|