@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,319 @@
1
+ /**
2
+ * Worker Registry
3
+ * Central registry for all background workers with lifecycle management
4
+ * Sealed namespace for immutability
5
+ */
6
+ import { ErrorFactory, Logger } from '@zintrust/core';
7
+ // Internal storage
8
+ const workers = new Map();
9
+ const registrations = new Map();
10
+ /**
11
+ * Helper: Calculate uptime in seconds
12
+ */
13
+ const calculateUptime = (startedAt) => {
14
+ if (!startedAt)
15
+ return null;
16
+ return Math.floor((Date.now() - startedAt.getTime()) / 1000);
17
+ };
18
+ /**
19
+ * Helper: Validate worker name
20
+ */
21
+ const validateWorkerName = (name) => {
22
+ if (!name || typeof name !== 'string') {
23
+ throw ErrorFactory.createWorkerError('Worker name must be a non-empty string');
24
+ }
25
+ if (!/^[a-z0-9-]+$/.test(name)) {
26
+ throw ErrorFactory.createWorkerError('Worker name must contain only lowercase letters, numbers, and hyphens');
27
+ }
28
+ };
29
+ /**
30
+ * Worker Registry - Sealed namespace
31
+ */
32
+ export const WorkerRegistry = Object.freeze({
33
+ /**
34
+ * Register a worker with the registry
35
+ */
36
+ register(options) {
37
+ validateWorkerName(options.name);
38
+ if (registrations.has(options.name)) {
39
+ Logger.warn(`Worker "${options.name}" is already registered. Skipping.`);
40
+ return;
41
+ }
42
+ registrations.set(options.name, options);
43
+ Logger.info(`Worker "${options.name}" registered successfully`);
44
+ },
45
+ /**
46
+ * Start a worker
47
+ */
48
+ async start(name, version) {
49
+ validateWorkerName(name);
50
+ const registration = registrations.get(name);
51
+ if (!registration) {
52
+ throw ErrorFactory.createWorkerError(`Worker "${name}" is not registered`);
53
+ }
54
+ if (workers.has(name)) {
55
+ const existing = workers.get(name);
56
+ if (existing?.metadata.status === 'running') {
57
+ Logger.warn(`Worker "${name}" is already running`);
58
+ return;
59
+ }
60
+ }
61
+ const versionSuffix = version === undefined ? '' : ` version ${version}`;
62
+ Logger.info(`Starting worker "${name}"${versionSuffix}...`);
63
+ try {
64
+ const instance = await registration.factory();
65
+ instance.metadata.status = 'starting';
66
+ instance.metadata.version = version ?? '1.0.0';
67
+ workers.set(name, instance);
68
+ instance.start();
69
+ instance.metadata.status = 'running';
70
+ instance.metadata.startedAt = new Date();
71
+ instance.metadata.stoppedAt = null;
72
+ Logger.info(`Worker "${name}" started successfully`);
73
+ }
74
+ catch (error) {
75
+ Logger.error(`Failed to start worker "${name}"`, error);
76
+ throw error;
77
+ }
78
+ },
79
+ /**
80
+ * Stop a worker
81
+ */
82
+ async stop(name) {
83
+ validateWorkerName(name);
84
+ const instance = workers.get(name);
85
+ if (!instance) {
86
+ Logger.warn(`Worker "${name}" is not running`);
87
+ return;
88
+ }
89
+ if (instance.metadata.status === 'stopped') {
90
+ Logger.warn(`Worker "${name}" is already stopped`);
91
+ return;
92
+ }
93
+ Logger.info(`Stopping worker "${name}"...`);
94
+ try {
95
+ instance.metadata.status = 'stopping';
96
+ await instance.stop();
97
+ instance.metadata.status = 'stopped';
98
+ instance.metadata.stoppedAt = new Date();
99
+ Logger.info(`Worker "${name}" stopped successfully`);
100
+ }
101
+ catch (error) {
102
+ Logger.error(`Failed to stop worker "${name}"`, error);
103
+ throw error;
104
+ }
105
+ },
106
+ /**
107
+ * Restart a worker (stop + start)
108
+ */
109
+ async restart(name) {
110
+ validateWorkerName(name);
111
+ const instance = workers.get(name);
112
+ if (instance) {
113
+ await WorkerRegistry.stop(name);
114
+ instance.metadata.restartCount += 1;
115
+ }
116
+ await WorkerRegistry.start(name);
117
+ Logger.info(`Worker "${name}" restarted successfully`);
118
+ },
119
+ /**
120
+ * Sleep a worker (pause processing but keep lock)
121
+ */
122
+ async sleep(name) {
123
+ validateWorkerName(name);
124
+ const instance = workers.get(name);
125
+ if (!instance) {
126
+ throw ErrorFactory.createWorkerError(`Worker "${name}" is not running`);
127
+ }
128
+ if (instance.metadata.status === 'sleeping') {
129
+ Logger.warn(`Worker "${name}" is already sleeping`);
130
+ return;
131
+ }
132
+ Logger.info(`Putting worker "${name}" to sleep...`);
133
+ try {
134
+ await instance.sleep();
135
+ instance.metadata.status = 'sleeping';
136
+ Logger.info(`Worker "${name}" is now sleeping`);
137
+ }
138
+ catch (error) {
139
+ Logger.error(`Failed to sleep worker "${name}"`, error);
140
+ throw error;
141
+ }
142
+ },
143
+ /**
144
+ * Wakeup a worker (resume from sleep)
145
+ */
146
+ async wakeup(name) {
147
+ validateWorkerName(name);
148
+ const instance = workers.get(name);
149
+ if (!instance) {
150
+ throw ErrorFactory.createWorkerError(`Worker "${name}" is not found`);
151
+ }
152
+ if (instance.metadata.status !== 'sleeping') {
153
+ Logger.warn(`Worker "${name}" is not sleeping (status: ${instance.metadata.status})`);
154
+ return;
155
+ }
156
+ Logger.info(`Waking up worker "${name}"...`);
157
+ try {
158
+ instance.wakeup();
159
+ instance.metadata.status = 'running';
160
+ Logger.info(`Worker "${name}" is now awake and running`);
161
+ }
162
+ catch (error) {
163
+ Logger.error(`Failed to wake up worker "${name}"`, error);
164
+ throw error;
165
+ }
166
+ },
167
+ /**
168
+ * Get worker status
169
+ */
170
+ status(name) {
171
+ validateWorkerName(name);
172
+ const instance = workers.get(name);
173
+ if (!instance) {
174
+ return null;
175
+ }
176
+ return { ...instance.metadata };
177
+ },
178
+ /**
179
+ * List all registered workers
180
+ */
181
+ list() {
182
+ return Array.from(registrations.keys());
183
+ },
184
+ /**
185
+ * List all running workers
186
+ */
187
+ listRunning() {
188
+ const running = [];
189
+ for (const [name, instance] of workers.entries()) {
190
+ if (instance.metadata.status === 'running') {
191
+ running.push(name);
192
+ }
193
+ }
194
+ return running;
195
+ },
196
+ /**
197
+ * Stop all running workers
198
+ */
199
+ async stopAll() {
200
+ Logger.info('Stopping all running workers...');
201
+ const running = WorkerRegistry.listRunning();
202
+ const tasks = running.map(async (name) => WorkerRegistry.stop(name));
203
+ try {
204
+ await Promise.all(tasks);
205
+ Logger.info(`Stopped ${running.length} workers successfully`);
206
+ }
207
+ catch (error) {
208
+ Logger.error('Failed to stop some workers', error);
209
+ throw error;
210
+ }
211
+ },
212
+ /**
213
+ * Get worker metrics
214
+ */
215
+ getMetrics(name) {
216
+ validateWorkerName(name);
217
+ const instance = workers.get(name);
218
+ if (!instance) {
219
+ return null;
220
+ }
221
+ return {
222
+ processedCount: instance.metadata.processedCount,
223
+ errorCount: instance.metadata.errorCount,
224
+ memoryUsage: instance.metadata.memoryUsage,
225
+ cpuUsage: instance.metadata.cpuUsage,
226
+ };
227
+ },
228
+ /**
229
+ * Get worker health status
230
+ */
231
+ getHealth(name) {
232
+ validateWorkerName(name);
233
+ const instance = workers.get(name);
234
+ if (!instance) {
235
+ return null;
236
+ }
237
+ return instance.getHealth();
238
+ },
239
+ /**
240
+ * Get registry snapshot
241
+ */
242
+ getSnapshot() {
243
+ const allWorkers = Array.from(workers.entries()).map(([name, instance]) => ({
244
+ name,
245
+ status: instance.metadata.status,
246
+ health: instance.getHealth(),
247
+ uptime: calculateUptime(instance.metadata.startedAt),
248
+ processedCount: instance.metadata.processedCount,
249
+ errorCount: instance.metadata.errorCount,
250
+ }));
251
+ const statusCounts = allWorkers.reduce((acc, w) => {
252
+ if (w.status === 'running')
253
+ acc.running++;
254
+ else if (w.status === 'stopped')
255
+ acc.stopped++;
256
+ else if (w.status === 'sleeping')
257
+ acc.sleeping++;
258
+ if (w.health === 'red')
259
+ acc.unhealthy++;
260
+ return acc;
261
+ }, { running: 0, stopped: 0, sleeping: 0, unhealthy: 0 });
262
+ return {
263
+ timestamp: new Date(),
264
+ totalWorkers: registrations.size,
265
+ runningWorkers: statusCounts.running,
266
+ stoppedWorkers: statusCounts.stopped,
267
+ sleepingWorkers: statusCounts.sleeping,
268
+ unhealthyWorkers: statusCounts.unhealthy,
269
+ workers: allWorkers,
270
+ };
271
+ },
272
+ /**
273
+ * Get worker topology (cluster view)
274
+ */
275
+ getTopology() {
276
+ const topology = {};
277
+ for (const [name, instance] of workers.entries()) {
278
+ const region = instance.metadata.region;
279
+ if (topology[region].count <= 0) {
280
+ topology[region] = { workers: [], count: 0 };
281
+ }
282
+ topology[region].workers.push(name);
283
+ topology[region].count++;
284
+ }
285
+ return topology;
286
+ },
287
+ /**
288
+ * Unregister a worker and clear its instance
289
+ */
290
+ unregister(name) {
291
+ validateWorkerName(name);
292
+ const instance = workers.get(name);
293
+ if (instance?.metadata.status === 'running') {
294
+ Logger.warn(`Worker "${name}" is still running during unregister`);
295
+ }
296
+ workers.delete(name);
297
+ registrations.delete(name);
298
+ Logger.info(`Worker "${name}" unregistered`);
299
+ },
300
+ /**
301
+ * Check if worker is registered
302
+ */
303
+ isRegistered(name) {
304
+ return registrations.has(name);
305
+ },
306
+ /**
307
+ * Check if worker is running
308
+ */
309
+ isRunning(name) {
310
+ const instance = workers.get(name);
311
+ return instance?.metadata.status === 'running';
312
+ },
313
+ /**
314
+ * Get worker instance (internal use)
315
+ */
316
+ getInstance(name) {
317
+ return workers.get(name) ?? null;
318
+ },
319
+ });
@@ -0,0 +1,61 @@
1
+ /**
2
+ * Worker Shutdown Coordinator
3
+ *
4
+ * Centralized graceful shutdown handling for the worker management system.
5
+ * Coordinates orderly shutdown of all worker modules and the WorkerFactory.
6
+ */
7
+ export interface IShutdownOptions {
8
+ /**
9
+ * Timeout for graceful shutdown in milliseconds
10
+ */
11
+ timeout?: number;
12
+ /**
13
+ * Whether to force exit after timeout
14
+ */
15
+ forceExit?: boolean;
16
+ /**
17
+ * Signal that triggered shutdown (SIGTERM, SIGINT, etc.)
18
+ */
19
+ signal?: string;
20
+ }
21
+ interface IShutdownState {
22
+ isShuttingDown: boolean;
23
+ completedAt: Date | null;
24
+ startedAt: Date | null;
25
+ reason: string | null;
26
+ }
27
+ /**
28
+ * Perform graceful shutdown of all worker modules
29
+ */
30
+ declare function shutdown(options?: IShutdownOptions): Promise<void>;
31
+ /**
32
+ * Register process signal handlers for graceful shutdown
33
+ */
34
+ declare function registerShutdownHandlers(): void;
35
+ /**
36
+ * Check if system is currently shutting down
37
+ */
38
+ declare function isShuttingDown(): boolean;
39
+ /**
40
+ * Get current shutdown state
41
+ */
42
+ declare function getShutdownState(): Readonly<IShutdownState>;
43
+ export declare const WorkerShutdown: Readonly<{
44
+ /**
45
+ * Perform graceful shutdown of all worker modules
46
+ */
47
+ shutdown: typeof shutdown;
48
+ /**
49
+ * Register process signal handlers for graceful shutdown
50
+ */
51
+ registerShutdownHandlers: typeof registerShutdownHandlers;
52
+ /**
53
+ * Check if system is currently shutting down
54
+ */
55
+ isShuttingDown: typeof isShuttingDown;
56
+ /**
57
+ * Get current shutdown state
58
+ */
59
+ getShutdownState: typeof getShutdownState;
60
+ }>;
61
+ export {};
@@ -0,0 +1,159 @@
1
+ /**
2
+ * Worker Shutdown Coordinator
3
+ *
4
+ * Centralized graceful shutdown handling for the worker management system.
5
+ * Coordinates orderly shutdown of all worker modules and the WorkerFactory.
6
+ */
7
+ import { Logger } from '@zintrust/core';
8
+ import { WorkerFactory } from './WorkerFactory';
9
+ // ============================================================================
10
+ // Implementation
11
+ // ============================================================================
12
+ const state = {
13
+ isShuttingDown: false,
14
+ completedAt: null,
15
+ startedAt: null,
16
+ reason: null,
17
+ };
18
+ let shutdownHandlersRegistered = false;
19
+ /**
20
+ * Perform graceful shutdown of all worker modules
21
+ */
22
+ async function shutdown(options = {}) {
23
+ const { timeout = 30000, forceExit = true, signal = 'unknown' } = options;
24
+ // Prevent concurrent shutdowns
25
+ if (state.isShuttingDown) {
26
+ Logger.warn('Shutdown already in progress, ignoring duplicate request');
27
+ return;
28
+ }
29
+ state.isShuttingDown = true;
30
+ state.startedAt = new Date();
31
+ state.reason = `Signal: ${signal}`;
32
+ Logger.info('🛑 Initiating graceful shutdown of worker management system', {
33
+ signal,
34
+ timeout,
35
+ forceExit,
36
+ });
37
+ // Setup timeout for forced shutdown
38
+ let timeoutHandle = null;
39
+ if (forceExit && timeout > 0) {
40
+ // eslint-disable-next-line no-restricted-syntax
41
+ timeoutHandle = setTimeout(() => {
42
+ Logger.error('❌ Graceful shutdown timeout exceeded, forcing exit', { timeout });
43
+ process.exit(1);
44
+ }, timeout);
45
+ }
46
+ try {
47
+ // Shutdown WorkerFactory - this will coordinate shutdown of all modules
48
+ await WorkerFactory.shutdown();
49
+ state.completedAt = new Date();
50
+ const duration = state.completedAt.getTime() - (state.startedAt?.getTime() ?? 0);
51
+ Logger.info('✅ Worker management system shutdown complete', {
52
+ duration: `${duration}ms`,
53
+ signal,
54
+ });
55
+ // Clear timeout if successful
56
+ if (timeoutHandle) {
57
+ clearTimeout(timeoutHandle);
58
+ }
59
+ }
60
+ catch (error) {
61
+ Logger.error('❌ Error during worker management system shutdown', error);
62
+ throw error;
63
+ }
64
+ }
65
+ /**
66
+ * Register process signal handlers for graceful shutdown
67
+ */
68
+ function registerShutdownHandlers() {
69
+ if (shutdownHandlersRegistered) {
70
+ Logger.debug('Shutdown handlers already registered, skipping');
71
+ return;
72
+ }
73
+ Logger.debug('Registering worker management system shutdown handlers');
74
+ // SIGTERM - graceful shutdown (Docker, systemd, etc.)
75
+ process.on('SIGTERM', async () => {
76
+ Logger.info('📨 Received SIGTERM signal');
77
+ try {
78
+ await shutdown({ signal: 'SIGTERM', timeout: 30000, forceExit: true });
79
+ }
80
+ catch (error) {
81
+ Logger.error('Error during SIGTERM shutdown', error);
82
+ }
83
+ });
84
+ // SIGINT - user interrupt (Ctrl+C) - REMOVED: handled by bootstrap.ts to prevent race condition
85
+ // process.on('SIGINT', async () => {
86
+ // Logger.info('📨 Received SIGINT signal');
87
+ // try {
88
+ // await shutdown({ signal: 'SIGINT', timeout: 30000, forceExit: true });
89
+ // } catch (error) {
90
+ // Logger.error('Error during SIGINT shutdown', error);
91
+ // }
92
+ // });
93
+ // SIGHUP - terminal closed
94
+ process.on('SIGHUP', async () => {
95
+ Logger.info('📨 Received SIGHUP signal');
96
+ try {
97
+ await shutdown({ signal: 'SIGHUP', timeout: 30000, forceExit: true });
98
+ }
99
+ catch (error) {
100
+ Logger.error('Error during SIGHUP shutdown', error);
101
+ }
102
+ });
103
+ // Handle uncaught errors during shutdown
104
+ process.on('uncaughtException', async (error) => {
105
+ Logger.error('💥 Uncaught exception during worker operations', error);
106
+ try {
107
+ await shutdown({ signal: 'uncaughtException', timeout: 10000, forceExit: true });
108
+ }
109
+ catch {
110
+ // Ignore errors during emergency shutdown
111
+ }
112
+ process.exit(1);
113
+ });
114
+ process.on('unhandledRejection', async (reason) => {
115
+ Logger.error('💥 Unhandled promise rejection during worker operations', reason);
116
+ try {
117
+ await shutdown({ signal: 'unhandledRejection', timeout: 10000, forceExit: true });
118
+ }
119
+ catch {
120
+ // Ignore errors during emergency shutdown
121
+ }
122
+ process.exit(1);
123
+ });
124
+ shutdownHandlersRegistered = true;
125
+ Logger.debug('Worker management system shutdown handlers registered');
126
+ }
127
+ /**
128
+ * Check if system is currently shutting down
129
+ */
130
+ function isShuttingDown() {
131
+ return state.isShuttingDown;
132
+ }
133
+ /**
134
+ * Get current shutdown state
135
+ */
136
+ function getShutdownState() {
137
+ return { ...state };
138
+ }
139
+ // ============================================================================
140
+ // Public API (Sealed Namespace)
141
+ // ============================================================================
142
+ export const WorkerShutdown = Object.freeze({
143
+ /**
144
+ * Perform graceful shutdown of all worker modules
145
+ */
146
+ shutdown,
147
+ /**
148
+ * Register process signal handlers for graceful shutdown
149
+ */
150
+ registerShutdownHandlers,
151
+ /**
152
+ * Check if system is currently shutting down
153
+ */
154
+ isShuttingDown,
155
+ /**
156
+ * Get current shutdown state
157
+ */
158
+ getShutdownState,
159
+ });
@@ -0,0 +1,107 @@
1
+ /**
2
+ * Worker Versioning System
3
+ * Semantic versioning support for workers with backward compatibility
4
+ * Sealed namespace for immutability
5
+ */
6
+ export type SemanticVersion = {
7
+ major: number;
8
+ minor: number;
9
+ patch: number;
10
+ prerelease?: string;
11
+ build?: string;
12
+ };
13
+ export type WorkerVersion = {
14
+ workerName: string;
15
+ version: SemanticVersion;
16
+ createdAt: Date;
17
+ deprecatedAt?: Date;
18
+ eolDate?: Date;
19
+ isActive: boolean;
20
+ isDeprecated: boolean;
21
+ migrationPath?: string;
22
+ changelog?: string;
23
+ breakingChanges?: string[];
24
+ };
25
+ export type VersionCompatibility = {
26
+ sourceVersion: SemanticVersion;
27
+ targetVersion: SemanticVersion;
28
+ compatible: boolean;
29
+ requiresMigration: boolean;
30
+ breakingChanges: string[];
31
+ recommendations: string[];
32
+ };
33
+ /**
34
+ * Worker Versioning - Sealed namespace
35
+ */
36
+ export declare const WorkerVersioning: Readonly<{
37
+ /**
38
+ * Register a worker version
39
+ */
40
+ register(workerVersion: Omit<WorkerVersion, "createdAt" | "isActive" | "isDeprecated">): void;
41
+ /**
42
+ * Get worker version
43
+ */
44
+ getVersion(workerName: string, versionStr: string): WorkerVersion | null;
45
+ /**
46
+ * Get all versions for a worker
47
+ */
48
+ getVersions(workerName: string, includeDeprecated?: boolean): ReadonlyArray<WorkerVersion>;
49
+ /**
50
+ * Get latest version
51
+ */
52
+ getLatest(workerName: string): WorkerVersion | null;
53
+ /**
54
+ * Deprecate a version
55
+ */
56
+ deprecate(workerName: string, versionStr: string, migrationPath?: string, eolDate?: Date): void;
57
+ /**
58
+ * Deactivate a version (stop accepting new jobs)
59
+ */
60
+ deactivate(workerName: string, versionStr: string): void;
61
+ /**
62
+ * Activate a version
63
+ */
64
+ activate(workerName: string, versionStr: string): void;
65
+ /**
66
+ * Check compatibility between versions
67
+ */
68
+ checkCompatibility(workerName: string, sourceVersionStr: string, targetVersionStr: string): VersionCompatibility;
69
+ /**
70
+ * Set version alias
71
+ */
72
+ setAlias(workerName: string, alias: string, versionStr: string): void;
73
+ /**
74
+ * Get version by alias
75
+ */
76
+ resolveAlias(workerName: string, alias: string): string | null;
77
+ /**
78
+ * Parse version string
79
+ */
80
+ parse(versionStr: string): SemanticVersion;
81
+ /**
82
+ * Convert version to string
83
+ */
84
+ stringify(version: SemanticVersion): string;
85
+ /**
86
+ * Compare two versions
87
+ */
88
+ compare(v1Str: string, v2Str: string): number;
89
+ /**
90
+ * Get version summary
91
+ */
92
+ getSummary(workerName: string): {
93
+ totalVersions: number;
94
+ activeVersions: number;
95
+ deprecatedVersions: number;
96
+ latest: string | null;
97
+ stable: string | null;
98
+ };
99
+ /**
100
+ * Clear all versions for a worker
101
+ */
102
+ clear(workerName: string): void;
103
+ /**
104
+ * Shutdown
105
+ */
106
+ shutdown(): void;
107
+ }>;