@zintrust/workers 0.1.27

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 (178) hide show
  1. package/README.md +861 -0
  2. package/dist/AnomalyDetection.d.ts +102 -0
  3. package/dist/AnomalyDetection.js +321 -0
  4. package/dist/AutoScaler.d.ts +127 -0
  5. package/dist/AutoScaler.js +425 -0
  6. package/dist/BroadcastWorker.d.ts +21 -0
  7. package/dist/BroadcastWorker.js +24 -0
  8. package/dist/CanaryController.d.ts +103 -0
  9. package/dist/CanaryController.js +380 -0
  10. package/dist/ChaosEngineering.d.ts +79 -0
  11. package/dist/ChaosEngineering.js +216 -0
  12. package/dist/CircuitBreaker.d.ts +106 -0
  13. package/dist/CircuitBreaker.js +374 -0
  14. package/dist/ClusterLock.d.ts +90 -0
  15. package/dist/ClusterLock.js +385 -0
  16. package/dist/ComplianceManager.d.ts +177 -0
  17. package/dist/ComplianceManager.js +556 -0
  18. package/dist/DatacenterOrchestrator.d.ts +133 -0
  19. package/dist/DatacenterOrchestrator.js +404 -0
  20. package/dist/DeadLetterQueue.d.ts +122 -0
  21. package/dist/DeadLetterQueue.js +539 -0
  22. package/dist/HealthMonitor.d.ts +42 -0
  23. package/dist/HealthMonitor.js +301 -0
  24. package/dist/MultiQueueWorker.d.ts +89 -0
  25. package/dist/MultiQueueWorker.js +277 -0
  26. package/dist/NotificationWorker.d.ts +21 -0
  27. package/dist/NotificationWorker.js +23 -0
  28. package/dist/Observability.d.ts +153 -0
  29. package/dist/Observability.js +530 -0
  30. package/dist/PluginManager.d.ts +123 -0
  31. package/dist/PluginManager.js +392 -0
  32. package/dist/PriorityQueue.d.ts +117 -0
  33. package/dist/PriorityQueue.js +244 -0
  34. package/dist/ResourceMonitor.d.ts +164 -0
  35. package/dist/ResourceMonitor.js +605 -0
  36. package/dist/SLAMonitor.d.ts +110 -0
  37. package/dist/SLAMonitor.js +274 -0
  38. package/dist/WorkerFactory.d.ts +193 -0
  39. package/dist/WorkerFactory.js +1507 -0
  40. package/dist/WorkerInit.d.ts +85 -0
  41. package/dist/WorkerInit.js +223 -0
  42. package/dist/WorkerMetrics.d.ts +114 -0
  43. package/dist/WorkerMetrics.js +509 -0
  44. package/dist/WorkerRegistry.d.ts +145 -0
  45. package/dist/WorkerRegistry.js +319 -0
  46. package/dist/WorkerShutdown.d.ts +61 -0
  47. package/dist/WorkerShutdown.js +159 -0
  48. package/dist/WorkerVersioning.d.ts +107 -0
  49. package/dist/WorkerVersioning.js +300 -0
  50. package/dist/build-manifest.json +462 -0
  51. package/dist/config/workerConfig.d.ts +3 -0
  52. package/dist/config/workerConfig.js +19 -0
  53. package/dist/createQueueWorker.d.ts +23 -0
  54. package/dist/createQueueWorker.js +113 -0
  55. package/dist/dashboard/index.d.ts +1 -0
  56. package/dist/dashboard/index.js +1 -0
  57. package/dist/dashboard/types.d.ts +117 -0
  58. package/dist/dashboard/types.js +1 -0
  59. package/dist/dashboard/workers-api.d.ts +4 -0
  60. package/dist/dashboard/workers-api.js +638 -0
  61. package/dist/dashboard/workers-dashboard-ui.d.ts +3 -0
  62. package/dist/dashboard/workers-dashboard-ui.js +1026 -0
  63. package/dist/dashboard/workers-dashboard.d.ts +4 -0
  64. package/dist/dashboard/workers-dashboard.js +904 -0
  65. package/dist/helper/index.d.ts +5 -0
  66. package/dist/helper/index.js +10 -0
  67. package/dist/http/WorkerApiController.d.ts +38 -0
  68. package/dist/http/WorkerApiController.js +312 -0
  69. package/dist/http/WorkerController.d.ts +374 -0
  70. package/dist/http/WorkerController.js +1351 -0
  71. package/dist/http/middleware/CustomValidation.d.ts +92 -0
  72. package/dist/http/middleware/CustomValidation.js +270 -0
  73. package/dist/http/middleware/DatacenterValidator.d.ts +3 -0
  74. package/dist/http/middleware/DatacenterValidator.js +94 -0
  75. package/dist/http/middleware/EditWorkerValidation.d.ts +7 -0
  76. package/dist/http/middleware/EditWorkerValidation.js +55 -0
  77. package/dist/http/middleware/FeaturesValidator.d.ts +3 -0
  78. package/dist/http/middleware/FeaturesValidator.js +60 -0
  79. package/dist/http/middleware/InfrastructureValidator.d.ts +31 -0
  80. package/dist/http/middleware/InfrastructureValidator.js +226 -0
  81. package/dist/http/middleware/OptionsValidator.d.ts +3 -0
  82. package/dist/http/middleware/OptionsValidator.js +112 -0
  83. package/dist/http/middleware/PayloadSanitizer.d.ts +7 -0
  84. package/dist/http/middleware/PayloadSanitizer.js +42 -0
  85. package/dist/http/middleware/ProcessorPathSanitizer.d.ts +3 -0
  86. package/dist/http/middleware/ProcessorPathSanitizer.js +74 -0
  87. package/dist/http/middleware/QueueNameSanitizer.d.ts +3 -0
  88. package/dist/http/middleware/QueueNameSanitizer.js +45 -0
  89. package/dist/http/middleware/ValidateDriver.d.ts +7 -0
  90. package/dist/http/middleware/ValidateDriver.js +20 -0
  91. package/dist/http/middleware/VersionSanitizer.d.ts +3 -0
  92. package/dist/http/middleware/VersionSanitizer.js +25 -0
  93. package/dist/http/middleware/WorkerNameSanitizer.d.ts +3 -0
  94. package/dist/http/middleware/WorkerNameSanitizer.js +46 -0
  95. package/dist/http/middleware/WorkerValidationChain.d.ts +27 -0
  96. package/dist/http/middleware/WorkerValidationChain.js +185 -0
  97. package/dist/index.d.ts +46 -0
  98. package/dist/index.js +48 -0
  99. package/dist/routes/workers.d.ts +12 -0
  100. package/dist/routes/workers.js +81 -0
  101. package/dist/storage/WorkerStore.d.ts +45 -0
  102. package/dist/storage/WorkerStore.js +195 -0
  103. package/dist/type.d.ts +76 -0
  104. package/dist/type.js +1 -0
  105. package/dist/ui/router/ui.d.ts +3 -0
  106. package/dist/ui/router/ui.js +83 -0
  107. package/dist/ui/types/worker-ui.d.ts +229 -0
  108. package/dist/ui/types/worker-ui.js +5 -0
  109. package/package.json +53 -0
  110. package/src/AnomalyDetection.ts +434 -0
  111. package/src/AutoScaler.ts +654 -0
  112. package/src/BroadcastWorker.ts +34 -0
  113. package/src/CanaryController.ts +531 -0
  114. package/src/ChaosEngineering.ts +301 -0
  115. package/src/CircuitBreaker.ts +495 -0
  116. package/src/ClusterLock.ts +499 -0
  117. package/src/ComplianceManager.ts +815 -0
  118. package/src/DatacenterOrchestrator.ts +561 -0
  119. package/src/DeadLetterQueue.ts +733 -0
  120. package/src/HealthMonitor.ts +390 -0
  121. package/src/MultiQueueWorker.ts +431 -0
  122. package/src/NotificationWorker.ts +33 -0
  123. package/src/Observability.ts +696 -0
  124. package/src/PluginManager.ts +551 -0
  125. package/src/PriorityQueue.ts +351 -0
  126. package/src/ResourceMonitor.ts +769 -0
  127. package/src/SLAMonitor.ts +408 -0
  128. package/src/WorkerFactory.ts +2108 -0
  129. package/src/WorkerInit.ts +313 -0
  130. package/src/WorkerMetrics.ts +709 -0
  131. package/src/WorkerRegistry.ts +443 -0
  132. package/src/WorkerShutdown.ts +210 -0
  133. package/src/WorkerVersioning.ts +422 -0
  134. package/src/config/workerConfig.ts +25 -0
  135. package/src/createQueueWorker.ts +174 -0
  136. package/src/dashboard/index.ts +6 -0
  137. package/src/dashboard/types.ts +141 -0
  138. package/src/dashboard/workers-api.ts +785 -0
  139. package/src/dashboard/zintrust.svg +30 -0
  140. package/src/helper/index.ts +11 -0
  141. package/src/http/WorkerApiController.ts +369 -0
  142. package/src/http/WorkerController.ts +1512 -0
  143. package/src/http/middleware/CustomValidation.ts +360 -0
  144. package/src/http/middleware/DatacenterValidator.ts +124 -0
  145. package/src/http/middleware/EditWorkerValidation.ts +74 -0
  146. package/src/http/middleware/FeaturesValidator.ts +82 -0
  147. package/src/http/middleware/InfrastructureValidator.ts +295 -0
  148. package/src/http/middleware/OptionsValidator.ts +144 -0
  149. package/src/http/middleware/PayloadSanitizer.ts +52 -0
  150. package/src/http/middleware/ProcessorPathSanitizer.ts +86 -0
  151. package/src/http/middleware/QueueNameSanitizer.ts +55 -0
  152. package/src/http/middleware/ValidateDriver.ts +29 -0
  153. package/src/http/middleware/VersionSanitizer.ts +30 -0
  154. package/src/http/middleware/WorkerNameSanitizer.ts +56 -0
  155. package/src/http/middleware/WorkerValidationChain.ts +230 -0
  156. package/src/index.ts +98 -0
  157. package/src/routes/workers.ts +154 -0
  158. package/src/storage/WorkerStore.ts +240 -0
  159. package/src/type.ts +89 -0
  160. package/src/types/queue-monitor.d.ts +38 -0
  161. package/src/types/queue-redis.d.ts +38 -0
  162. package/src/ui/README.md +13 -0
  163. package/src/ui/components/JsonEditor.js +670 -0
  164. package/src/ui/components/JsonViewer.js +387 -0
  165. package/src/ui/components/WorkerCard.js +178 -0
  166. package/src/ui/components/WorkerExpandPanel.js +257 -0
  167. package/src/ui/components/fetcher.js +42 -0
  168. package/src/ui/components/sla-scorecard.js +32 -0
  169. package/src/ui/components/styles.css +30 -0
  170. package/src/ui/components/table-expander.js +34 -0
  171. package/src/ui/integration/worker-ui-integration.js +565 -0
  172. package/src/ui/router/ui.ts +99 -0
  173. package/src/ui/services/workerApi.js +240 -0
  174. package/src/ui/types/worker-ui.ts +283 -0
  175. package/src/ui/utils/jsonValidator.js +444 -0
  176. package/src/ui/workers/index.html +202 -0
  177. package/src/ui/workers/main.js +1781 -0
  178. package/src/ui/workers/styles.css +1350 -0
@@ -0,0 +1,431 @@
1
+ /**
2
+ * Multi-Queue Worker Support
3
+ * Enable workers to process multiple queues with different priorities
4
+ * Sealed namespace for immutability
5
+ */
6
+
7
+ import { ErrorFactory, Logger } from '@zintrust/core';
8
+ import { Worker, type Job, type WorkerOptions } from 'bullmq';
9
+ import { PriorityQueue } from './PriorityQueue';
10
+
11
+ export type QueueConfig = {
12
+ name: string;
13
+ concurrency: number;
14
+ priority: number; // Higher number = higher priority
15
+ enabled: boolean;
16
+ rateLimit?: {
17
+ max: number; // Max jobs per duration
18
+ duration: number; // Duration in milliseconds
19
+ };
20
+ };
21
+
22
+ export type MultiQueueWorkerConfig = {
23
+ workerName: string;
24
+ queues: QueueConfig[];
25
+ processor: (job: Job) => Promise<unknown>;
26
+ sharedConcurrency?: number; // Total concurrency across all queues
27
+ defaultConcurrency?: number; // Default per-queue if not specified
28
+ };
29
+
30
+ export type QueueStats = {
31
+ queueName: string;
32
+ processed: number;
33
+ failed: number;
34
+ active: number;
35
+ waiting: number;
36
+ enabled: boolean;
37
+ lastProcessedAt?: Date;
38
+ };
39
+
40
+ // Internal state
41
+ const multiQueueWorkers = new Map<
42
+ string,
43
+ {
44
+ config: MultiQueueWorkerConfig;
45
+ workers: Map<string, Worker>;
46
+ stats: Map<string, QueueStats>;
47
+ }
48
+ >();
49
+
50
+ /**
51
+ * Helper: Create worker for a queue
52
+ */
53
+ const createQueueWorker = (
54
+ workerName: string,
55
+ queueConfig: QueueConfig,
56
+ processor: MultiQueueWorkerConfig['processor']
57
+ ): Worker => {
58
+ const queue = PriorityQueue.getQueueInstance(queueConfig.name);
59
+ const connection = queue.opts.connection;
60
+
61
+ const workerOptions: WorkerOptions = {
62
+ connection,
63
+ concurrency: queueConfig.concurrency,
64
+ limiter: queueConfig.rateLimit,
65
+ autorun: queueConfig.enabled,
66
+ prefix: queue.opts.prefix,
67
+ };
68
+
69
+ const worker = new Worker(
70
+ queueConfig.name,
71
+ async (job: Job) => {
72
+ Logger.debug(`Processing job from queue: ${queueConfig.name}`, {
73
+ jobId: job.id,
74
+ workerName,
75
+ });
76
+
77
+ return processor(job);
78
+ },
79
+ workerOptions
80
+ );
81
+
82
+ // Set up event listeners
83
+ worker.on('completed', (job: Job) => {
84
+ const stats = multiQueueWorkers.get(workerName)?.stats.get(queueConfig.name);
85
+ if (stats) {
86
+ stats.processed++;
87
+ stats.lastProcessedAt = new Date();
88
+ }
89
+
90
+ Logger.debug(`Job completed from queue: ${queueConfig.name}`, {
91
+ jobId: job.id,
92
+ workerName,
93
+ });
94
+ });
95
+
96
+ worker.on('failed', (job: Job | undefined, error: Error) => {
97
+ const stats = multiQueueWorkers.get(workerName)?.stats.get(queueConfig.name);
98
+ if (stats) {
99
+ stats.failed++;
100
+ }
101
+
102
+ Logger.error(`Job failed from queue: ${queueConfig.name}`, error, 'workers');
103
+ Logger.debug('Queue job failure details', {
104
+ jobId: job?.id,
105
+ workerName,
106
+ queueName: queueConfig.name,
107
+ });
108
+ });
109
+
110
+ worker.on('active', (_job: Job) => {
111
+ const stats = multiQueueWorkers.get(workerName)?.stats.get(queueConfig.name);
112
+ if (stats) {
113
+ stats.active++;
114
+ }
115
+ });
116
+
117
+ return worker;
118
+ };
119
+
120
+ /**
121
+ * Helper: Initialize stats for queue
122
+ */
123
+ const initializeQueueStats = (queueName: string, enabled: boolean): QueueStats => {
124
+ return {
125
+ queueName,
126
+ processed: 0,
127
+ failed: 0,
128
+ active: 0,
129
+ waiting: 0,
130
+ enabled,
131
+ };
132
+ };
133
+
134
+ /**
135
+ * Multi-Queue Worker Manager - Sealed namespace
136
+ */
137
+ export const MultiQueueWorker = Object.freeze({
138
+ /**
139
+ * Create multi-queue worker
140
+ */
141
+ create(config: MultiQueueWorkerConfig): void {
142
+ if (multiQueueWorkers.has(config.workerName)) {
143
+ throw ErrorFactory.createWorkerError(
144
+ `Multi-queue worker "${config.workerName}" already exists`
145
+ );
146
+ }
147
+
148
+ const workers = new Map<string, Worker>();
149
+ const stats = new Map<string, QueueStats>();
150
+
151
+ // Sort queues by priority (higher first)
152
+ const sortedQueues = [...config.queues].sort((a, b) => b.priority - a.priority);
153
+
154
+ // Create workers for each queue
155
+ for (const queueConfig of sortedQueues) {
156
+ const worker = createQueueWorker(config.workerName, queueConfig, config.processor);
157
+ workers.set(queueConfig.name, worker);
158
+ stats.set(queueConfig.name, initializeQueueStats(queueConfig.name, queueConfig.enabled));
159
+ }
160
+
161
+ multiQueueWorkers.set(config.workerName, {
162
+ config,
163
+ workers,
164
+ stats,
165
+ });
166
+
167
+ Logger.info(`Multi-queue worker created: ${config.workerName}`, {
168
+ queues: sortedQueues.map((q) => q.name),
169
+ totalConcurrency: sortedQueues.reduce((sum, q) => sum + q.concurrency, 0),
170
+ });
171
+ },
172
+
173
+ /**
174
+ * Start processing for a specific queue
175
+ */
176
+ async startQueue(workerName: string, queueName: string): Promise<void> {
177
+ const mqw = multiQueueWorkers.get(workerName);
178
+
179
+ if (!mqw) {
180
+ throw ErrorFactory.createNotFoundError(`Multi-queue worker "${workerName}" not found`);
181
+ }
182
+
183
+ const worker = mqw.workers.get(queueName);
184
+
185
+ if (!worker) {
186
+ throw ErrorFactory.createNotFoundError(
187
+ `Queue "${queueName}" not found in worker "${workerName}"`
188
+ );
189
+ }
190
+
191
+ await worker.run();
192
+
193
+ const stats = mqw.stats.get(queueName);
194
+ if (stats) {
195
+ stats.enabled = true;
196
+ }
197
+
198
+ Logger.info(`Queue started: ${queueName}`, { workerName });
199
+ },
200
+
201
+ /**
202
+ * Stop processing for a specific queue
203
+ */
204
+ async stopQueue(workerName: string, queueName: string): Promise<void> {
205
+ const mqw = multiQueueWorkers.get(workerName);
206
+
207
+ if (!mqw) {
208
+ throw ErrorFactory.createNotFoundError(`Multi-queue worker "${workerName}" not found`);
209
+ }
210
+
211
+ const worker = mqw.workers.get(queueName);
212
+
213
+ if (!worker) {
214
+ throw ErrorFactory.createNotFoundError(
215
+ `Queue "${queueName}" not found in worker "${workerName}"`
216
+ );
217
+ }
218
+
219
+ await worker.pause();
220
+
221
+ const stats = mqw.stats.get(queueName);
222
+ if (stats) {
223
+ stats.enabled = false;
224
+ }
225
+
226
+ Logger.info(`Queue stopped: ${queueName}`, { workerName });
227
+ },
228
+
229
+ /**
230
+ * Start all queues
231
+ */
232
+ async startAll(workerName: string): Promise<void> {
233
+ const mqw = multiQueueWorkers.get(workerName);
234
+
235
+ if (!mqw) {
236
+ throw ErrorFactory.createNotFoundError(`Multi-queue worker "${workerName}" not found`);
237
+ }
238
+
239
+ const promises = Array.from(mqw.workers.keys()).map(async (queueName) =>
240
+ MultiQueueWorker.startQueue(workerName, queueName)
241
+ );
242
+
243
+ await Promise.all(promises);
244
+
245
+ Logger.info(`All queues started for worker: ${workerName}`);
246
+ },
247
+
248
+ /**
249
+ * Stop all queues
250
+ */
251
+ async stopAll(workerName: string): Promise<void> {
252
+ const mqw = multiQueueWorkers.get(workerName);
253
+
254
+ if (!mqw) {
255
+ throw ErrorFactory.createNotFoundError(`Multi-queue worker "${workerName}" not found`);
256
+ }
257
+
258
+ const promises = Array.from(mqw.workers.keys()).map(async (queueName) =>
259
+ MultiQueueWorker.stopQueue(workerName, queueName)
260
+ );
261
+
262
+ await Promise.all(promises);
263
+
264
+ Logger.info(`All queues stopped for worker: ${workerName}`);
265
+ },
266
+
267
+ /**
268
+ * Update queue priority
269
+ */
270
+ updateQueuePriority(workerName: string, queueName: string, priority: number): void {
271
+ const mqw = multiQueueWorkers.get(workerName);
272
+
273
+ if (!mqw) {
274
+ throw ErrorFactory.createNotFoundError(`Multi-queue worker "${workerName}" not found`);
275
+ }
276
+
277
+ const queueConfig = mqw.config.queues.find((q) => q.name === queueName);
278
+
279
+ if (!queueConfig) {
280
+ throw ErrorFactory.createNotFoundError(
281
+ `Queue "${queueName}" not found in worker "${workerName}"`
282
+ );
283
+ }
284
+
285
+ queueConfig.priority = priority;
286
+
287
+ Logger.info(`Queue priority updated: ${queueName}`, { workerName, priority });
288
+ },
289
+
290
+ /**
291
+ * Update queue concurrency
292
+ */
293
+ async updateQueueConcurrency(
294
+ workerName: string,
295
+ queueName: string,
296
+ concurrency: number
297
+ ): Promise<void> {
298
+ const mqw = multiQueueWorkers.get(workerName);
299
+
300
+ if (!mqw) {
301
+ throw ErrorFactory.createNotFoundError(`Multi-queue worker "${workerName}" not found`);
302
+ }
303
+
304
+ const worker = mqw.workers.get(queueName);
305
+
306
+ if (!worker) {
307
+ throw ErrorFactory.createNotFoundError(
308
+ `Queue "${queueName}" not found in worker "${workerName}"`
309
+ );
310
+ }
311
+
312
+ const queueConfig = mqw.config.queues.find((q) => q.name === queueName);
313
+
314
+ if (!queueConfig) {
315
+ throw ErrorFactory.createNotFoundError(
316
+ `Queue "${queueName}" not found in worker "${workerName}"`
317
+ );
318
+ }
319
+
320
+ queueConfig.concurrency = concurrency;
321
+
322
+ // Update worker concurrency (requires restart in BullMQ)
323
+ await worker.close();
324
+
325
+ const newWorker = createQueueWorker(workerName, queueConfig, mqw.config.processor);
326
+ mqw.workers.set(queueName, newWorker);
327
+
328
+ Logger.info(`Queue concurrency updated: ${queueName}`, { workerName, concurrency });
329
+ },
330
+
331
+ /**
332
+ * Get stats for a queue
333
+ */
334
+ async getQueueStats(workerName: string, queueName: string): Promise<QueueStats> {
335
+ const mqw = multiQueueWorkers.get(workerName);
336
+
337
+ if (!mqw) {
338
+ throw ErrorFactory.createNotFoundError(`Multi-queue worker "${workerName}" not found`);
339
+ }
340
+
341
+ const stats = mqw.stats.get(queueName);
342
+
343
+ if (!stats) {
344
+ throw ErrorFactory.createNotFoundError(
345
+ `Stats for queue "${queueName}" not found in worker "${workerName}"`
346
+ );
347
+ }
348
+
349
+ // Update waiting count from queue
350
+ PriorityQueue.getQueueInstance(queueName);
351
+ const queueInfo = await PriorityQueue.getQueueInfo(queueName);
352
+
353
+ stats.waiting = queueInfo.jobCounts.waiting;
354
+
355
+ return { ...stats };
356
+ },
357
+
358
+ /**
359
+ * Get stats for all queues
360
+ */
361
+ async getAllStats(workerName: string): Promise<ReadonlyArray<QueueStats>> {
362
+ const mqw = multiQueueWorkers.get(workerName);
363
+
364
+ if (!mqw) {
365
+ throw ErrorFactory.createNotFoundError(`Multi-queue worker "${workerName}" not found`);
366
+ }
367
+
368
+ const allStats = await Promise.all(
369
+ Array.from(mqw.workers.keys()).map(async (queueName) =>
370
+ MultiQueueWorker.getQueueStats(workerName, queueName)
371
+ )
372
+ );
373
+
374
+ return allStats;
375
+ },
376
+
377
+ /**
378
+ * Get configuration
379
+ */
380
+ getConfig(workerName: string): MultiQueueWorkerConfig | null {
381
+ const mqw = multiQueueWorkers.get(workerName);
382
+ return mqw ? { ...mqw.config } : null;
383
+ },
384
+
385
+ /**
386
+ * List all multi-queue workers
387
+ */
388
+ list(): string[] {
389
+ return Array.from(multiQueueWorkers.keys());
390
+ },
391
+
392
+ /**
393
+ * Remove multi-queue worker
394
+ */
395
+ async remove(workerName: string): Promise<void> {
396
+ const mqw = multiQueueWorkers.get(workerName);
397
+
398
+ if (!mqw) {
399
+ throw ErrorFactory.createNotFoundError(`Multi-queue worker "${workerName}" not found`);
400
+ }
401
+
402
+ // Close all workers
403
+ const closePromises = Array.from(mqw.workers.values()).map(async (worker) => worker.close());
404
+
405
+ await Promise.all(closePromises);
406
+
407
+ multiQueueWorkers.delete(workerName);
408
+
409
+ Logger.info(`Multi-queue worker removed: ${workerName}`);
410
+ },
411
+
412
+ /**
413
+ * Shutdown all multi-queue workers
414
+ */
415
+ async shutdown(): Promise<void> {
416
+ Logger.info('MultiQueueWorker shutting down...');
417
+
418
+ const shutdownPromises = Array.from(multiQueueWorkers.values()).map(async (mqw) => {
419
+ const closePromises = Array.from(mqw.workers.values()).map(async (worker) => worker.close());
420
+ await Promise.all(closePromises);
421
+ });
422
+
423
+ await Promise.all(shutdownPromises);
424
+
425
+ multiQueueWorkers.clear();
426
+
427
+ Logger.info('MultiQueueWorker shutdown complete');
428
+ },
429
+ });
430
+
431
+ // Graceful shutdown handled by WorkerShutdown
@@ -0,0 +1,33 @@
1
+ /**
2
+ * NotificationWorker - Processes queued notifications
3
+ *
4
+ * This worker dequeues notification messages and sends them using the Notification service.
5
+ * Use with Queue.dequeue() in a background process or cron job.
6
+ */
7
+
8
+ import { Notification } from '@zintrust/core';
9
+ import { createQueueWorker } from './createQueueWorker';
10
+
11
+ type NotificationJob = {
12
+ recipient: string;
13
+ message: string;
14
+ options: Record<string, unknown>;
15
+ timestamp: number;
16
+ };
17
+
18
+ export const NotificationWorker = Object.freeze({
19
+ ...createQueueWorker<NotificationJob>({
20
+ kindLabel: 'notification',
21
+ defaultQueueName: 'notifications',
22
+ maxAttempts: 3,
23
+ getLogFields: (payload) => ({
24
+ recipient: payload.recipient,
25
+ queuedAt: payload.timestamp,
26
+ }),
27
+ handle: async (payload) => {
28
+ await Notification.send(payload.recipient, payload.message, payload.options);
29
+ },
30
+ }),
31
+ });
32
+
33
+ export default NotificationWorker;