servcraft 0.1.0 → 0.1.3

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.
Files changed (217) hide show
  1. package/.claude/settings.local.json +30 -0
  2. package/.github/CODEOWNERS +18 -0
  3. package/.github/PULL_REQUEST_TEMPLATE.md +46 -0
  4. package/.github/dependabot.yml +59 -0
  5. package/.github/workflows/ci.yml +188 -0
  6. package/.github/workflows/release.yml +195 -0
  7. package/AUDIT.md +602 -0
  8. package/LICENSE +21 -0
  9. package/README.md +1102 -1
  10. package/dist/cli/index.cjs +2026 -2168
  11. package/dist/cli/index.cjs.map +1 -1
  12. package/dist/cli/index.js +2026 -2168
  13. package/dist/cli/index.js.map +1 -1
  14. package/dist/index.cjs +595 -616
  15. package/dist/index.cjs.map +1 -1
  16. package/dist/index.d.cts +114 -52
  17. package/dist/index.d.ts +114 -52
  18. package/dist/index.js +595 -616
  19. package/dist/index.js.map +1 -1
  20. package/docs/CLI-001_MULTI_DB_PLAN.md +546 -0
  21. package/docs/DATABASE_MULTI_ORM.md +399 -0
  22. package/docs/PHASE1_BREAKDOWN.md +346 -0
  23. package/docs/PROGRESS.md +550 -0
  24. package/docs/modules/ANALYTICS.md +226 -0
  25. package/docs/modules/API-VERSIONING.md +252 -0
  26. package/docs/modules/AUDIT.md +192 -0
  27. package/docs/modules/AUTH.md +431 -0
  28. package/docs/modules/CACHE.md +346 -0
  29. package/docs/modules/EMAIL.md +254 -0
  30. package/docs/modules/FEATURE-FLAG.md +291 -0
  31. package/docs/modules/I18N.md +294 -0
  32. package/docs/modules/MEDIA-PROCESSING.md +281 -0
  33. package/docs/modules/MFA.md +266 -0
  34. package/docs/modules/NOTIFICATION.md +311 -0
  35. package/docs/modules/OAUTH.md +237 -0
  36. package/docs/modules/PAYMENT.md +804 -0
  37. package/docs/modules/QUEUE.md +540 -0
  38. package/docs/modules/RATE-LIMIT.md +339 -0
  39. package/docs/modules/SEARCH.md +288 -0
  40. package/docs/modules/SECURITY.md +327 -0
  41. package/docs/modules/SESSION.md +382 -0
  42. package/docs/modules/SWAGGER.md +305 -0
  43. package/docs/modules/UPLOAD.md +296 -0
  44. package/docs/modules/USER.md +505 -0
  45. package/docs/modules/VALIDATION.md +294 -0
  46. package/docs/modules/WEBHOOK.md +270 -0
  47. package/docs/modules/WEBSOCKET.md +691 -0
  48. package/package.json +53 -38
  49. package/prisma/schema.prisma +395 -1
  50. package/src/cli/commands/add-module.ts +520 -87
  51. package/src/cli/commands/db.ts +3 -4
  52. package/src/cli/commands/docs.ts +256 -6
  53. package/src/cli/commands/generate.ts +12 -19
  54. package/src/cli/commands/init.ts +384 -214
  55. package/src/cli/index.ts +0 -4
  56. package/src/cli/templates/repository.ts +6 -1
  57. package/src/cli/templates/routes.ts +6 -21
  58. package/src/cli/utils/docs-generator.ts +6 -7
  59. package/src/cli/utils/env-manager.ts +717 -0
  60. package/src/cli/utils/field-parser.ts +16 -7
  61. package/src/cli/utils/interactive-prompt.ts +223 -0
  62. package/src/cli/utils/template-manager.ts +346 -0
  63. package/src/config/database.config.ts +183 -0
  64. package/src/config/env.ts +0 -10
  65. package/src/config/index.ts +0 -14
  66. package/src/core/server.ts +1 -1
  67. package/src/database/adapters/mongoose.adapter.ts +132 -0
  68. package/src/database/adapters/prisma.adapter.ts +118 -0
  69. package/src/database/connection.ts +190 -0
  70. package/src/database/interfaces/database.interface.ts +85 -0
  71. package/src/database/interfaces/index.ts +7 -0
  72. package/src/database/interfaces/repository.interface.ts +129 -0
  73. package/src/database/models/mongoose/index.ts +7 -0
  74. package/src/database/models/mongoose/payment.schema.ts +347 -0
  75. package/src/database/models/mongoose/user.schema.ts +154 -0
  76. package/src/database/prisma.ts +1 -4
  77. package/src/database/redis.ts +101 -0
  78. package/src/database/repositories/mongoose/index.ts +7 -0
  79. package/src/database/repositories/mongoose/payment.repository.ts +380 -0
  80. package/src/database/repositories/mongoose/user.repository.ts +255 -0
  81. package/src/database/seed.ts +6 -1
  82. package/src/index.ts +9 -20
  83. package/src/middleware/security.ts +2 -6
  84. package/src/modules/analytics/analytics.routes.ts +80 -0
  85. package/src/modules/analytics/analytics.service.ts +364 -0
  86. package/src/modules/analytics/index.ts +18 -0
  87. package/src/modules/analytics/types.ts +180 -0
  88. package/src/modules/api-versioning/index.ts +15 -0
  89. package/src/modules/api-versioning/types.ts +86 -0
  90. package/src/modules/api-versioning/versioning.middleware.ts +120 -0
  91. package/src/modules/api-versioning/versioning.routes.ts +54 -0
  92. package/src/modules/api-versioning/versioning.service.ts +189 -0
  93. package/src/modules/audit/audit.repository.ts +206 -0
  94. package/src/modules/audit/audit.service.ts +27 -59
  95. package/src/modules/auth/auth.controller.ts +2 -2
  96. package/src/modules/auth/auth.middleware.ts +3 -9
  97. package/src/modules/auth/auth.routes.ts +10 -107
  98. package/src/modules/auth/auth.service.ts +126 -23
  99. package/src/modules/auth/index.ts +3 -4
  100. package/src/modules/cache/cache.service.ts +367 -0
  101. package/src/modules/cache/index.ts +10 -0
  102. package/src/modules/cache/types.ts +44 -0
  103. package/src/modules/email/email.service.ts +3 -10
  104. package/src/modules/email/templates.ts +2 -8
  105. package/src/modules/feature-flag/feature-flag.repository.ts +303 -0
  106. package/src/modules/feature-flag/feature-flag.routes.ts +247 -0
  107. package/src/modules/feature-flag/feature-flag.service.ts +566 -0
  108. package/src/modules/feature-flag/index.ts +20 -0
  109. package/src/modules/feature-flag/types.ts +192 -0
  110. package/src/modules/i18n/i18n.middleware.ts +186 -0
  111. package/src/modules/i18n/i18n.routes.ts +191 -0
  112. package/src/modules/i18n/i18n.service.ts +456 -0
  113. package/src/modules/i18n/index.ts +18 -0
  114. package/src/modules/i18n/types.ts +118 -0
  115. package/src/modules/media-processing/index.ts +17 -0
  116. package/src/modules/media-processing/media-processing.routes.ts +111 -0
  117. package/src/modules/media-processing/media-processing.service.ts +245 -0
  118. package/src/modules/media-processing/types.ts +156 -0
  119. package/src/modules/mfa/index.ts +20 -0
  120. package/src/modules/mfa/mfa.repository.ts +206 -0
  121. package/src/modules/mfa/mfa.routes.ts +595 -0
  122. package/src/modules/mfa/mfa.service.ts +572 -0
  123. package/src/modules/mfa/totp.ts +150 -0
  124. package/src/modules/mfa/types.ts +57 -0
  125. package/src/modules/notification/index.ts +20 -0
  126. package/src/modules/notification/notification.repository.ts +356 -0
  127. package/src/modules/notification/notification.service.ts +483 -0
  128. package/src/modules/notification/types.ts +119 -0
  129. package/src/modules/oauth/index.ts +20 -0
  130. package/src/modules/oauth/oauth.repository.ts +219 -0
  131. package/src/modules/oauth/oauth.routes.ts +446 -0
  132. package/src/modules/oauth/oauth.service.ts +293 -0
  133. package/src/modules/oauth/providers/apple.provider.ts +250 -0
  134. package/src/modules/oauth/providers/facebook.provider.ts +181 -0
  135. package/src/modules/oauth/providers/github.provider.ts +248 -0
  136. package/src/modules/oauth/providers/google.provider.ts +189 -0
  137. package/src/modules/oauth/providers/twitter.provider.ts +214 -0
  138. package/src/modules/oauth/types.ts +94 -0
  139. package/src/modules/payment/index.ts +19 -0
  140. package/src/modules/payment/payment.repository.ts +733 -0
  141. package/src/modules/payment/payment.routes.ts +390 -0
  142. package/src/modules/payment/payment.service.ts +354 -0
  143. package/src/modules/payment/providers/mobile-money.provider.ts +274 -0
  144. package/src/modules/payment/providers/paypal.provider.ts +190 -0
  145. package/src/modules/payment/providers/stripe.provider.ts +215 -0
  146. package/src/modules/payment/types.ts +140 -0
  147. package/src/modules/queue/cron.ts +438 -0
  148. package/src/modules/queue/index.ts +87 -0
  149. package/src/modules/queue/queue.routes.ts +600 -0
  150. package/src/modules/queue/queue.service.ts +842 -0
  151. package/src/modules/queue/types.ts +222 -0
  152. package/src/modules/queue/workers.ts +366 -0
  153. package/src/modules/rate-limit/index.ts +59 -0
  154. package/src/modules/rate-limit/rate-limit.middleware.ts +134 -0
  155. package/src/modules/rate-limit/rate-limit.routes.ts +269 -0
  156. package/src/modules/rate-limit/rate-limit.service.ts +348 -0
  157. package/src/modules/rate-limit/stores/memory.store.ts +165 -0
  158. package/src/modules/rate-limit/stores/redis.store.ts +322 -0
  159. package/src/modules/rate-limit/types.ts +153 -0
  160. package/src/modules/search/adapters/elasticsearch.adapter.ts +326 -0
  161. package/src/modules/search/adapters/meilisearch.adapter.ts +261 -0
  162. package/src/modules/search/adapters/memory.adapter.ts +278 -0
  163. package/src/modules/search/index.ts +21 -0
  164. package/src/modules/search/search.service.ts +234 -0
  165. package/src/modules/search/types.ts +214 -0
  166. package/src/modules/security/index.ts +40 -0
  167. package/src/modules/security/sanitize.ts +223 -0
  168. package/src/modules/security/security-audit.service.ts +388 -0
  169. package/src/modules/security/security.middleware.ts +398 -0
  170. package/src/modules/session/index.ts +3 -0
  171. package/src/modules/session/session.repository.ts +159 -0
  172. package/src/modules/session/session.service.ts +340 -0
  173. package/src/modules/session/types.ts +38 -0
  174. package/src/modules/swagger/index.ts +7 -1
  175. package/src/modules/swagger/schema-builder.ts +16 -4
  176. package/src/modules/swagger/swagger.service.ts +9 -10
  177. package/src/modules/swagger/types.ts +0 -2
  178. package/src/modules/upload/index.ts +14 -0
  179. package/src/modules/upload/types.ts +83 -0
  180. package/src/modules/upload/upload.repository.ts +199 -0
  181. package/src/modules/upload/upload.routes.ts +311 -0
  182. package/src/modules/upload/upload.service.ts +448 -0
  183. package/src/modules/user/index.ts +3 -3
  184. package/src/modules/user/user.controller.ts +15 -9
  185. package/src/modules/user/user.repository.ts +237 -113
  186. package/src/modules/user/user.routes.ts +39 -164
  187. package/src/modules/user/user.service.ts +4 -3
  188. package/src/modules/validation/validator.ts +12 -17
  189. package/src/modules/webhook/index.ts +91 -0
  190. package/src/modules/webhook/retry.ts +196 -0
  191. package/src/modules/webhook/signature.ts +135 -0
  192. package/src/modules/webhook/types.ts +181 -0
  193. package/src/modules/webhook/webhook.repository.ts +358 -0
  194. package/src/modules/webhook/webhook.routes.ts +442 -0
  195. package/src/modules/webhook/webhook.service.ts +457 -0
  196. package/src/modules/websocket/features.ts +504 -0
  197. package/src/modules/websocket/index.ts +106 -0
  198. package/src/modules/websocket/middlewares.ts +298 -0
  199. package/src/modules/websocket/types.ts +181 -0
  200. package/src/modules/websocket/websocket.service.ts +692 -0
  201. package/src/utils/errors.ts +7 -0
  202. package/src/utils/pagination.ts +4 -1
  203. package/tests/helpers/db-check.ts +79 -0
  204. package/tests/integration/auth-redis.test.ts +94 -0
  205. package/tests/integration/cache-redis.test.ts +387 -0
  206. package/tests/integration/mongoose-repositories.test.ts +410 -0
  207. package/tests/integration/payment-prisma.test.ts +637 -0
  208. package/tests/integration/queue-bullmq.test.ts +417 -0
  209. package/tests/integration/user-prisma.test.ts +441 -0
  210. package/tests/integration/websocket-socketio.test.ts +552 -0
  211. package/tests/setup.ts +11 -9
  212. package/vitest.config.ts +3 -8
  213. package/npm-cache/_cacache/content-v2/sha512/1c/d0/03440d500a0487621aad1d6402978340698976602046db8e24fa03c01ee6c022c69b0582f969042d9442ee876ac35c038e960dd427d1e622fa24b8eb7dba +0 -0
  214. package/npm-cache/_cacache/content-v2/sha512/42/55/28b493ca491833e5aab0e9c3108d29ab3f36c248ca88f45d4630674fce9130959e56ae308797ac2b6328fa7f09a610b9550ed09cb971d039876d293fc69d +0 -0
  215. package/npm-cache/_cacache/content-v2/sha512/e0/12/f360dc9315ee5f17844a0c8c233ee6bf7c30837c4a02ea0d56c61c7f7ab21c0e958e50ed2c57c59f983c762b93056778c9009b2398ffc26def0183999b13 +0 -0
  216. package/npm-cache/_cacache/content-v2/sha512/ed/b0/fae1161902898f4c913c67d7f6cdf6be0665aec3b389b9c4f4f0a101ca1da59badf1b59c4e0030f5223023b8d63cfe501c46a32c20c895d4fb3f11ca2232 +0 -0
  217. package/npm-cache/_cacache/index-v5/58/94/c2cba79e0f16b4c10e95a87e32255741149e8222cc314a476aab67c39cc0 +0 -5
@@ -0,0 +1,540 @@
1
+ # Queue Module Documentation
2
+
3
+ ## Overview
4
+
5
+ The Queue module provides robust background job processing using **BullMQ** with **Redis** persistence. This ensures jobs are never lost, even if the server restarts, and supports horizontal scaling across multiple instances.
6
+
7
+ ## Features
8
+
9
+ - **Persistent Storage**: All jobs stored in Redis, surviving server restarts
10
+ - **Automatic Retries**: Configurable retry strategies with exponential backoff
11
+ - **Job Prioritization**: Critical, high, normal, and low priority levels
12
+ - **Delayed Jobs**: Schedule jobs to run at specific times
13
+ - **Repeatable Jobs**: Cron-based recurring job scheduling
14
+ - **Concurrency Control**: Limit parallel execution per worker
15
+ - **Real-time Events**: Monitor job lifecycle with events
16
+ - **Metrics Collection**: Track throughput, success rates, and processing times
17
+ - **Multi-instance Safe**: Safe for horizontal scaling with multiple server instances
18
+ - **Graceful Shutdown**: Wait for active jobs before closing
19
+
20
+ ## Installation
21
+
22
+ BullMQ and ioredis are already included in ServCraft dependencies:
23
+
24
+ ```bash
25
+ npm install bullmq ioredis
26
+ ```
27
+
28
+ ## Configuration
29
+
30
+ ### Environment Variables
31
+
32
+ ```env
33
+ # Redis connection for queues
34
+ REDIS_HOST=localhost
35
+ REDIS_PORT=6379
36
+ REDIS_PASSWORD=your_password
37
+ REDIS_DB=0
38
+ ```
39
+
40
+ ### Service Configuration
41
+
42
+ ```typescript
43
+ import { QueueService } from '@servcraft/queue';
44
+
45
+ const queueService = new QueueService({
46
+ redis: {
47
+ host: process.env.REDIS_HOST || 'localhost',
48
+ port: parseInt(process.env.REDIS_PORT || '6379', 10),
49
+ password: process.env.REDIS_PASSWORD,
50
+ db: 0,
51
+ },
52
+ prefix: 'myapp:queue', // Redis key prefix
53
+ metrics: true, // Enable metrics collection
54
+ defaultJobOptions: {
55
+ attempts: 3,
56
+ backoff: {
57
+ type: 'exponential',
58
+ delay: 1000,
59
+ },
60
+ removeOnComplete: true,
61
+ removeOnFail: false,
62
+ timeout: 60000,
63
+ },
64
+ });
65
+ ```
66
+
67
+ ## Basic Usage
68
+
69
+ ### Creating a Queue
70
+
71
+ ```typescript
72
+ // Create a queue (or get existing one)
73
+ const queue = queueService.createQueue('emails');
74
+ ```
75
+
76
+ ### Adding Jobs
77
+
78
+ ```typescript
79
+ // Simple job
80
+ const job = await queueService.addJob('emails', 'send-welcome', {
81
+ userId: 'user-123',
82
+ email: 'user@example.com',
83
+ template: 'welcome',
84
+ });
85
+
86
+ console.log(`Job ${job.id} added`);
87
+ ```
88
+
89
+ ### Adding Jobs with Options
90
+
91
+ ```typescript
92
+ // High priority job
93
+ await queueService.addJob('emails', 'send-critical', data, {
94
+ priority: 'critical', // critical, high, normal, low
95
+ });
96
+
97
+ // Delayed job (runs in 5 minutes)
98
+ await queueService.addJob('notifications', 'reminder', data, {
99
+ delay: 5 * 60 * 1000,
100
+ });
101
+
102
+ // Job with custom retry settings
103
+ await queueService.addJob('webhooks', 'send-webhook', data, {
104
+ attempts: 5,
105
+ backoff: {
106
+ type: 'exponential',
107
+ delay: 2000, // 2s, 4s, 8s, 16s, 32s
108
+ },
109
+ });
110
+
111
+ // Repeatable job (every hour)
112
+ await queueService.addJob('reports', 'generate-daily', data, {
113
+ repeat: {
114
+ every: 60 * 60 * 1000, // every hour
115
+ },
116
+ });
117
+
118
+ // Cron job (every day at midnight)
119
+ await queueService.addJob('cleanup', 'remove-old-files', data, {
120
+ repeat: {
121
+ cron: '0 0 * * *',
122
+ },
123
+ });
124
+ ```
125
+
126
+ ### Adding Bulk Jobs
127
+
128
+ ```typescript
129
+ const jobs = await queueService.addBulkJobs('emails', {
130
+ jobs: [
131
+ { name: 'send-email', data: { userId: '1', type: 'welcome' } },
132
+ { name: 'send-email', data: { userId: '2', type: 'welcome' } },
133
+ { name: 'send-email', data: { userId: '3', type: 'welcome' } },
134
+ ],
135
+ });
136
+
137
+ console.log(`Added ${jobs.length} jobs`);
138
+ ```
139
+
140
+ ### Registering Workers
141
+
142
+ ```typescript
143
+ import type { Job, Worker } from '@servcraft/queue';
144
+
145
+ // Simple worker
146
+ const emailWorker: Worker = {
147
+ name: 'send-welcome',
148
+ process: async (job: Job) => {
149
+ const { userId, email, template } = job.data;
150
+
151
+ // Process the job
152
+ await sendEmail(email, template);
153
+
154
+ return { sent: true, email };
155
+ },
156
+ concurrency: 5, // Process 5 emails in parallel
157
+ };
158
+
159
+ queueService.registerWorker('emails', emailWorker);
160
+ ```
161
+
162
+ ### Worker with Progress Updates
163
+
164
+ ```typescript
165
+ const imageWorker: Worker = {
166
+ name: 'process-image',
167
+ process: async (job: Job) => {
168
+ const { imageUrl, operations } = job.data;
169
+
170
+ // Update progress
171
+ await queueService.updateJobProgress('images', job.id, 0);
172
+
173
+ // Perform operations
174
+ for (let i = 0; i < operations.length; i++) {
175
+ await performOperation(operations[i]);
176
+ await queueService.updateJobProgress(
177
+ 'images',
178
+ job.id,
179
+ Math.round(((i + 1) / operations.length) * 100)
180
+ );
181
+ }
182
+
183
+ return { processed: true };
184
+ },
185
+ concurrency: 2,
186
+ };
187
+
188
+ queueService.registerWorker('images', imageWorker);
189
+ ```
190
+
191
+ ## Job Management
192
+
193
+ ### Get Job by ID
194
+
195
+ ```typescript
196
+ const job = await queueService.getJob('emails', 'job-id-123');
197
+ console.log(job.status); // waiting, active, completed, failed, delayed
198
+ ```
199
+
200
+ ### List Jobs
201
+
202
+ ```typescript
203
+ // List waiting jobs
204
+ const waitingJobs = await queueService.listJobs('emails', {
205
+ status: 'waiting',
206
+ });
207
+
208
+ // List failed jobs
209
+ const failedJobs = await queueService.listJobs('emails', {
210
+ status: 'failed',
211
+ });
212
+
213
+ // List with filters
214
+ const filteredJobs = await queueService.listJobs('emails', {
215
+ status: ['waiting', 'active'],
216
+ name: 'send-welcome',
217
+ limit: 50,
218
+ offset: 0,
219
+ });
220
+ ```
221
+
222
+ ### Retry Failed Jobs
223
+
224
+ ```typescript
225
+ // Retry a specific failed job
226
+ await queueService.retryJob('emails', 'failed-job-id');
227
+ ```
228
+
229
+ ### Remove Jobs
230
+
231
+ ```typescript
232
+ // Remove a job (cannot remove active jobs)
233
+ await queueService.removeJob('emails', 'job-id');
234
+ ```
235
+
236
+ ### Clean Old Jobs
237
+
238
+ ```typescript
239
+ // Clean completed jobs older than 24 hours
240
+ const cleaned = await queueService.cleanJobs('emails', 'completed', 24 * 60 * 60 * 1000);
241
+ console.log(`Cleaned ${cleaned} jobs`);
242
+
243
+ // Clean both completed and failed jobs
244
+ await queueService.cleanJobs('emails', ['completed', 'failed'], 7 * 24 * 60 * 60 * 1000);
245
+ ```
246
+
247
+ ## Queue Operations
248
+
249
+ ### Pause/Resume Queue
250
+
251
+ ```typescript
252
+ // Pause queue (stops processing new jobs)
253
+ await queueService.pauseQueue('emails');
254
+
255
+ // Resume queue
256
+ await queueService.resumeQueue('emails');
257
+ ```
258
+
259
+ ### Drain Queue
260
+
261
+ ```typescript
262
+ // Remove all waiting jobs
263
+ await queueService.drainQueue('emails');
264
+ ```
265
+
266
+ ### Obliterate Queue
267
+
268
+ ```typescript
269
+ // Completely remove queue and all its data
270
+ await queueService.obliterateQueue('emails');
271
+ ```
272
+
273
+ ## Statistics and Metrics
274
+
275
+ ### Queue Statistics
276
+
277
+ ```typescript
278
+ const stats = await queueService.getStats('emails');
279
+ console.log({
280
+ waiting: stats.waiting,
281
+ active: stats.active,
282
+ completed: stats.completed,
283
+ failed: stats.failed,
284
+ delayed: stats.delayed,
285
+ paused: stats.paused,
286
+ });
287
+ ```
288
+
289
+ ### Queue Metrics
290
+
291
+ ```typescript
292
+ const metrics = await queueService.getMetrics('emails');
293
+ console.log({
294
+ totalProcessed: metrics.totalProcessed,
295
+ totalFailed: metrics.totalFailed,
296
+ successRate: metrics.successRate,
297
+ avgProcessingTime: metrics.avgProcessingTime,
298
+ currentConcurrency: metrics.currentConcurrency,
299
+ peakConcurrency: metrics.peakConcurrency,
300
+ });
301
+ ```
302
+
303
+ ## Events
304
+
305
+ ### Subscribe to Job Events
306
+
307
+ ```typescript
308
+ // Listen for specific events
309
+ queueService.on('added', (event) => {
310
+ console.log(`Job ${event.jobId} added`);
311
+ });
312
+
313
+ queueService.on('active', (event) => {
314
+ console.log(`Job ${event.jobId} started processing`);
315
+ });
316
+
317
+ queueService.on('completed', (event) => {
318
+ console.log(`Job ${event.jobId} completed with:`, event.data);
319
+ });
320
+
321
+ queueService.on('failed', (event) => {
322
+ console.log(`Job ${event.jobId} failed:`, event.data);
323
+ });
324
+
325
+ queueService.on('progress', (event) => {
326
+ console.log(`Job ${event.jobId} progress:`, event.data);
327
+ });
328
+
329
+ queueService.on('stalled', (event) => {
330
+ console.log(`Job ${event.jobId} stalled`);
331
+ });
332
+
333
+ // Listen for all events
334
+ queueService.on('job:event', (event) => {
335
+ console.log(`Event ${event.event} for job ${event.jobId}`);
336
+ });
337
+ ```
338
+
339
+ ## Graceful Shutdown
340
+
341
+ ```typescript
342
+ // In your server shutdown handler
343
+ process.on('SIGTERM', async () => {
344
+ console.log('Shutting down...');
345
+
346
+ // Wait for active jobs to complete
347
+ await queueService.close();
348
+
349
+ console.log('Queue service closed');
350
+ process.exit(0);
351
+ });
352
+ ```
353
+
354
+ ## Common Use Cases
355
+
356
+ ### Email Queue
357
+
358
+ ```typescript
359
+ // Add email job
360
+ await queueService.addJob('emails', 'send-email', {
361
+ to: 'user@example.com',
362
+ subject: 'Welcome!',
363
+ template: 'welcome',
364
+ data: { name: 'John' },
365
+ });
366
+
367
+ // Email worker
368
+ queueService.registerWorker('emails', {
369
+ name: 'send-email',
370
+ process: async (job) => {
371
+ const { to, subject, template, data } = job.data;
372
+ await emailService.send(to, subject, template, data);
373
+ return { sent: true };
374
+ },
375
+ concurrency: 10,
376
+ });
377
+ ```
378
+
379
+ ### Webhook Delivery
380
+
381
+ ```typescript
382
+ // Add webhook job with retries
383
+ await queueService.addJob('webhooks', 'deliver', {
384
+ url: 'https://api.example.com/webhook',
385
+ payload: { event: 'user.created', data: { id: '123' } },
386
+ }, {
387
+ attempts: 5,
388
+ backoff: { type: 'exponential', delay: 1000 },
389
+ });
390
+
391
+ // Webhook worker
392
+ queueService.registerWorker('webhooks', {
393
+ name: 'deliver',
394
+ process: async (job) => {
395
+ const { url, payload } = job.data;
396
+ const response = await fetch(url, {
397
+ method: 'POST',
398
+ headers: { 'Content-Type': 'application/json' },
399
+ body: JSON.stringify(payload),
400
+ });
401
+
402
+ if (!response.ok) {
403
+ throw new Error(`Webhook failed: ${response.status}`);
404
+ }
405
+
406
+ return { delivered: true, status: response.status };
407
+ },
408
+ concurrency: 5,
409
+ });
410
+ ```
411
+
412
+ ### Image Processing
413
+
414
+ ```typescript
415
+ // Add image processing job
416
+ await queueService.addJob('images', 'process', {
417
+ source: '/uploads/image.jpg',
418
+ operations: [
419
+ { type: 'resize', width: 800 },
420
+ { type: 'compress', quality: 80 },
421
+ ],
422
+ output: '/processed/image.webp',
423
+ });
424
+
425
+ // Image worker
426
+ queueService.registerWorker('images', {
427
+ name: 'process',
428
+ process: async (job) => {
429
+ const { source, operations, output } = job.data;
430
+ await imageProcessor.process(source, operations, output);
431
+ return { processed: true, output };
432
+ },
433
+ concurrency: 2, // CPU-intensive, limit concurrency
434
+ });
435
+ ```
436
+
437
+ ### Scheduled Reports
438
+
439
+ ```typescript
440
+ // Daily report at 6 AM
441
+ await queueService.addJob('reports', 'daily-summary', {
442
+ type: 'daily',
443
+ }, {
444
+ repeat: { cron: '0 6 * * *' },
445
+ });
446
+
447
+ // Report worker
448
+ queueService.registerWorker('reports', {
449
+ name: 'daily-summary',
450
+ process: async (job) => {
451
+ const report = await generateReport(job.data.type);
452
+ await sendReportEmail(report);
453
+ return { generated: true };
454
+ },
455
+ concurrency: 1,
456
+ });
457
+ ```
458
+
459
+ ## Best Practices
460
+
461
+ 1. **Use Meaningful Queue Names**: Group related jobs in named queues (e.g., `emails`, `webhooks`, `reports`)
462
+
463
+ 2. **Set Appropriate Concurrency**: CPU-intensive tasks should have lower concurrency
464
+
465
+ 3. **Configure Retries**: Always set retry attempts for jobs that may fail temporarily
466
+
467
+ 4. **Use Exponential Backoff**: Prevents overwhelming external services during failures
468
+
469
+ 5. **Clean Old Jobs**: Periodically clean completed/failed jobs to manage Redis memory
470
+
471
+ 6. **Monitor Metrics**: Track success rates and processing times to identify issues
472
+
473
+ 7. **Implement Graceful Shutdown**: Always wait for active jobs before closing
474
+
475
+ 8. **Use Job Progress**: For long-running jobs, update progress to show status
476
+
477
+ ## Troubleshooting
478
+
479
+ ### Jobs Not Processing
480
+
481
+ 1. Check Redis connection: `queueService.isConnected()`
482
+ 2. Verify worker is registered for the job name
483
+ 3. Check if queue is paused: `await queueService.getStats(queueName)`
484
+
485
+ ### Jobs Stuck in Active State
486
+
487
+ Jobs may be stalled if workers crash. BullMQ automatically handles stalled jobs and retries them.
488
+
489
+ ### High Memory Usage in Redis
490
+
491
+ Clean old completed/failed jobs regularly:
492
+ ```typescript
493
+ await queueService.cleanJobs('queueName', ['completed', 'failed'], 7 * 24 * 60 * 60 * 1000);
494
+ ```
495
+
496
+ ### Connection Errors
497
+
498
+ Ensure Redis is running and accessible. Check connection info:
499
+ ```typescript
500
+ console.log(queueService.getConnectionInfo());
501
+ ```
502
+
503
+ ## API Reference
504
+
505
+ ### QueueService Methods
506
+
507
+ | Method | Description |
508
+ |--------|-------------|
509
+ | `createQueue(name)` | Create or get a queue |
510
+ | `addJob(queue, name, data, options?)` | Add a job |
511
+ | `addBulkJobs(queue, options)` | Add multiple jobs |
512
+ | `registerWorker(queue, worker)` | Register a worker |
513
+ | `getJob(queue, jobId)` | Get job by ID |
514
+ | `listJobs(queue, filter?)` | List jobs with filters |
515
+ | `removeJob(queue, jobId)` | Remove a job |
516
+ | `retryJob(queue, jobId)` | Retry a failed job |
517
+ | `cleanJobs(queue, status, olderThanMs)` | Clean old jobs |
518
+ | `getStats(queue)` | Get queue statistics |
519
+ | `getMetrics(queue)` | Get queue metrics |
520
+ | `pauseQueue(queue)` | Pause a queue |
521
+ | `resumeQueue(queue)` | Resume a queue |
522
+ | `drainQueue(queue)` | Remove all waiting jobs |
523
+ | `obliterateQueue(queue)` | Delete queue and all data |
524
+ | `listQueues()` | List all queues |
525
+ | `close()` | Graceful shutdown |
526
+ | `isConnected()` | Check connection status |
527
+ | `getConnectionInfo()` | Get connection details |
528
+
529
+ ### Job Options
530
+
531
+ | Option | Type | Description |
532
+ |--------|------|-------------|
533
+ | `priority` | `'critical' \| 'high' \| 'normal' \| 'low'` | Job priority |
534
+ | `delay` | `number` | Delay in milliseconds |
535
+ | `attempts` | `number` | Max retry attempts |
536
+ | `backoff` | `{ type: 'fixed' \| 'exponential', delay: number }` | Retry backoff strategy |
537
+ | `removeOnComplete` | `boolean \| number` | Remove job on completion |
538
+ | `removeOnFail` | `boolean \| number` | Remove job on failure |
539
+ | `timeout` | `number` | Job timeout in milliseconds |
540
+ | `repeat` | `{ cron?: string, every?: number, limit?: number }` | Repeat configuration |