@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,495 @@
1
+ /**
2
+ * Circuit Breaker Pattern
3
+ * Fault tolerance with version tracking and automatic recovery
4
+ * Sealed namespace for immutability
5
+ */
6
+
7
+ import { Logger } from '@zintrust/core';
8
+
9
+ export type CircuitState = 'closed' | 'open' | 'half-open';
10
+
11
+ export type CircuitBreakerConfig = {
12
+ failureThreshold: number; // Number of failures before opening
13
+ successThreshold: number; // Number of successes to close from half-open
14
+ timeout: number; // Time in ms before attempting to recover (half-open)
15
+ resetTimeout: number; // Time in ms to reset failure count in closed state
16
+ volumeThreshold: number; // Minimum requests before considering failure rate
17
+ };
18
+
19
+ export type CircuitBreakerState = {
20
+ workerName: string;
21
+ version: string;
22
+ state: CircuitState;
23
+ failureCount: number;
24
+ successCount: number;
25
+ totalRequests: number;
26
+ lastFailureTime: Date | null;
27
+ lastSuccessTime: Date | null;
28
+ lastStateChange: Date;
29
+ nextRetryTime: Date | null;
30
+ errorRate: number;
31
+ };
32
+
33
+ export type CircuitBreakerEvent = {
34
+ workerName: string;
35
+ version: string;
36
+ event: 'opened' | 'closed' | 'half-open' | 'success' | 'failure' | 'rejected';
37
+ state: CircuitState;
38
+ timestamp: Date;
39
+ reason?: string;
40
+ error?: Error;
41
+ };
42
+
43
+ // Internal state
44
+ const circuits = new Map<string, CircuitBreakerState>();
45
+ const eventHistory = new Map<string, CircuitBreakerEvent[]>();
46
+ const defaultConfig: CircuitBreakerConfig = {
47
+ failureThreshold: 5,
48
+ successThreshold: 3,
49
+ timeout: 60000, // 1 minute
50
+ resetTimeout: 300000, // 5 minutes
51
+ volumeThreshold: 10,
52
+ };
53
+
54
+ /**
55
+ * Helper: Get circuit key
56
+ */
57
+ const getCircuitKey = (workerName: string, version: string): string => {
58
+ return `${workerName}:${version}`;
59
+ };
60
+
61
+ /**
62
+ * Helper: Record event
63
+ */
64
+ const recordEvent = (event: CircuitBreakerEvent): void => {
65
+ const key = getCircuitKey(event.workerName, event.version);
66
+ let history = eventHistory.get(key);
67
+
68
+ if (!history) {
69
+ history = [];
70
+ eventHistory.set(key, history);
71
+ }
72
+
73
+ history.push(event);
74
+
75
+ // Keep only last 1000 events
76
+ if (history.length > 1000) {
77
+ history.shift();
78
+ }
79
+
80
+ Logger.debug(`Circuit breaker event: ${event.workerName}:${event.version} - ${event.event}`, {
81
+ state: event.state,
82
+ reason: event.reason,
83
+ });
84
+ };
85
+
86
+ /**
87
+ * Helper: Transition to new state
88
+ */
89
+ const transitionState = (
90
+ circuit: CircuitBreakerState,
91
+ newState: CircuitState,
92
+ reason: string
93
+ ): void => {
94
+ const oldState = circuit.state;
95
+ circuit.state = newState;
96
+ circuit.lastStateChange = new Date();
97
+
98
+ if (newState === 'open') {
99
+ circuit.nextRetryTime = new Date(Date.now() + defaultConfig.timeout);
100
+ } else if (newState === 'closed') {
101
+ circuit.failureCount = 0;
102
+ circuit.successCount = 0;
103
+ circuit.nextRetryTime = null;
104
+ } else if (newState === 'half-open') {
105
+ circuit.successCount = 0;
106
+ circuit.nextRetryTime = null;
107
+ }
108
+
109
+ Logger.info(`Circuit breaker state transition: ${circuit.workerName}:${circuit.version}`, {
110
+ from: oldState,
111
+ to: newState,
112
+ reason,
113
+ });
114
+
115
+ const eventType: CircuitBreakerEvent['event'] = newState === 'open' ? 'opened' : newState;
116
+
117
+ recordEvent({
118
+ workerName: circuit.workerName,
119
+ version: circuit.version,
120
+ event: eventType,
121
+ state: newState,
122
+ timestamp: new Date(),
123
+ reason,
124
+ });
125
+ };
126
+
127
+ /**
128
+ * Helper: Calculate error rate
129
+ */
130
+ const calculateErrorRate = (circuit: CircuitBreakerState): number => {
131
+ if (circuit.totalRequests === 0) {
132
+ return 0;
133
+ }
134
+
135
+ return (circuit.failureCount / circuit.totalRequests) * 100;
136
+ };
137
+
138
+ /**
139
+ * Helper: Check if should reset failure count
140
+ */
141
+ const shouldResetFailureCount = (circuit: CircuitBreakerState): boolean => {
142
+ if (!circuit.lastFailureTime) {
143
+ return false;
144
+ }
145
+
146
+ const timeSinceLastFailure = Date.now() - circuit.lastFailureTime.getTime();
147
+ return timeSinceLastFailure > defaultConfig.resetTimeout;
148
+ };
149
+
150
+ /**
151
+ * Circuit Breaker - Sealed namespace
152
+ */
153
+ export const CircuitBreaker = Object.freeze({
154
+ /**
155
+ * Initialize circuit breaker for a worker version
156
+ */
157
+ initialize(workerName: string, version: string): void {
158
+ const key = getCircuitKey(workerName, version);
159
+
160
+ if (circuits.has(key)) {
161
+ Logger.debug(`Circuit breaker already exists: ${key}`);
162
+ return;
163
+ }
164
+
165
+ const circuit: CircuitBreakerState = {
166
+ workerName,
167
+ version,
168
+ state: 'closed',
169
+ failureCount: 0,
170
+ successCount: 0,
171
+ totalRequests: 0,
172
+ lastFailureTime: null,
173
+ lastSuccessTime: null,
174
+ lastStateChange: new Date(),
175
+ nextRetryTime: null,
176
+ errorRate: 0,
177
+ };
178
+
179
+ circuits.set(key, circuit);
180
+
181
+ Logger.info(`Circuit breaker initialized: ${key}`);
182
+ },
183
+
184
+ /**
185
+ * Check if circuit allows execution
186
+ */
187
+ canExecute(workerName: string, version: string): boolean {
188
+ const key = getCircuitKey(workerName, version);
189
+ const circuit = circuits.get(key);
190
+
191
+ if (!circuit) {
192
+ // No circuit exists, create and allow
193
+ CircuitBreaker.initialize(workerName, version);
194
+ return true;
195
+ }
196
+
197
+ const now = Date.now();
198
+
199
+ // Reset failure count if enough time has passed
200
+ if (circuit.state === 'closed' && shouldResetFailureCount(circuit)) {
201
+ circuit.failureCount = 0;
202
+ circuit.totalRequests = 0;
203
+ Logger.debug(`Reset failure count for ${key}`);
204
+ }
205
+
206
+ switch (circuit.state) {
207
+ case 'closed':
208
+ return true;
209
+
210
+ case 'open':
211
+ // Check if timeout has passed to try half-open
212
+ if (circuit.nextRetryTime && now >= circuit.nextRetryTime.getTime()) {
213
+ transitionState(circuit, 'half-open', 'Timeout elapsed, attempting recovery');
214
+ return true;
215
+ }
216
+ return false;
217
+
218
+ case 'half-open':
219
+ // Allow limited requests to test recovery
220
+ return true;
221
+ }
222
+ },
223
+
224
+ /**
225
+ * Record successful execution
226
+ */
227
+ recordSuccess(workerName: string, version: string): void {
228
+ const key = getCircuitKey(workerName, version);
229
+ const circuit = circuits.get(key);
230
+
231
+ if (!circuit) {
232
+ CircuitBreaker.initialize(workerName, version);
233
+ return;
234
+ }
235
+
236
+ circuit.successCount++;
237
+ circuit.totalRequests++;
238
+ circuit.lastSuccessTime = new Date();
239
+ circuit.errorRate = calculateErrorRate(circuit);
240
+
241
+ recordEvent({
242
+ workerName,
243
+ version,
244
+ event: 'success',
245
+ state: circuit.state,
246
+ timestamp: new Date(),
247
+ });
248
+
249
+ // Transition based on state
250
+ if (circuit.state === 'half-open') {
251
+ if (circuit.successCount >= defaultConfig.successThreshold) {
252
+ transitionState(circuit, 'closed', `${circuit.successCount} consecutive successes`);
253
+ }
254
+ }
255
+ },
256
+
257
+ /**
258
+ * Record failed execution
259
+ */
260
+ recordFailure(workerName: string, version: string, error: Error): void {
261
+ const key = getCircuitKey(workerName, version);
262
+ const circuit = circuits.get(key);
263
+
264
+ if (!circuit) {
265
+ CircuitBreaker.initialize(workerName, version);
266
+ return;
267
+ }
268
+
269
+ circuit.failureCount++;
270
+ circuit.totalRequests++;
271
+ circuit.lastFailureTime = new Date();
272
+ circuit.errorRate = calculateErrorRate(circuit);
273
+
274
+ recordEvent({
275
+ workerName,
276
+ version,
277
+ event: 'failure',
278
+ state: circuit.state,
279
+ timestamp: new Date(),
280
+ error,
281
+ });
282
+
283
+ // Transition based on state and thresholds
284
+ if (circuit.state === 'half-open') {
285
+ // Any failure in half-open reopens the circuit
286
+ transitionState(circuit, 'open', 'Failure during recovery attempt');
287
+ } else if (circuit.state === 'closed') {
288
+ // Check if should open based on failure threshold
289
+ if (circuit.totalRequests >= defaultConfig.volumeThreshold) {
290
+ if (circuit.failureCount >= defaultConfig.failureThreshold) {
291
+ transitionState(
292
+ circuit,
293
+ 'open',
294
+ `Failure threshold exceeded: ${circuit.failureCount}/${defaultConfig.failureThreshold}`
295
+ );
296
+ }
297
+ }
298
+ }
299
+ },
300
+
301
+ /**
302
+ * Record rejected execution (when circuit is open)
303
+ */
304
+ recordRejection(workerName: string, version: string): void {
305
+ const key = getCircuitKey(workerName, version);
306
+ const circuit = circuits.get(key);
307
+
308
+ if (!circuit) {
309
+ return;
310
+ }
311
+
312
+ recordEvent({
313
+ workerName,
314
+ version,
315
+ event: 'rejected',
316
+ state: circuit.state,
317
+ timestamp: new Date(),
318
+ reason: 'Circuit breaker is open',
319
+ });
320
+ },
321
+
322
+ /**
323
+ * Get circuit state
324
+ */
325
+ getState(workerName: string, version: string): CircuitBreakerState | null {
326
+ const key = getCircuitKey(workerName, version);
327
+ const circuit = circuits.get(key);
328
+
329
+ return circuit ? { ...circuit } : null;
330
+ },
331
+
332
+ /**
333
+ * Get all circuit states
334
+ */
335
+ getAllStates(): ReadonlyArray<CircuitBreakerState> {
336
+ return Array.from(circuits.values()).map((circuit) => ({ ...circuit }));
337
+ },
338
+
339
+ /**
340
+ * Get circuit states by worker name (all versions)
341
+ */
342
+ getStatesByWorker(workerName: string): ReadonlyArray<CircuitBreakerState> {
343
+ const states: CircuitBreakerState[] = [];
344
+
345
+ for (const circuit of circuits.values()) {
346
+ if (circuit.workerName === workerName) {
347
+ states.push({ ...circuit });
348
+ }
349
+ }
350
+
351
+ return states;
352
+ },
353
+
354
+ /**
355
+ * Get event history
356
+ */
357
+ getEventHistory(
358
+ workerName: string,
359
+ version: string,
360
+ limit = 100
361
+ ): ReadonlyArray<CircuitBreakerEvent> {
362
+ const key = getCircuitKey(workerName, version);
363
+ const history = eventHistory.get(key) ?? [];
364
+
365
+ return history.slice(-limit).map((event) => ({ ...event }));
366
+ },
367
+
368
+ /**
369
+ * Manually reset circuit to closed state
370
+ */
371
+ reset(workerName: string, version: string): void {
372
+ const key = getCircuitKey(workerName, version);
373
+ const circuit = circuits.get(key);
374
+
375
+ if (!circuit) {
376
+ Logger.warn(`Circuit breaker not found: ${key}`);
377
+ return;
378
+ }
379
+
380
+ transitionState(circuit, 'closed', 'Manual reset');
381
+ circuit.failureCount = 0;
382
+ circuit.successCount = 0;
383
+ circuit.totalRequests = 0;
384
+ circuit.errorRate = 0;
385
+
386
+ Logger.info(`Circuit breaker manually reset: ${key}`);
387
+ },
388
+
389
+ /**
390
+ * Manually force circuit to open state
391
+ */
392
+ forceOpen(workerName: string, version: string, reason: string): void {
393
+ const key = getCircuitKey(workerName, version);
394
+ const circuit = circuits.get(key);
395
+
396
+ if (!circuit) {
397
+ CircuitBreaker.initialize(workerName, version);
398
+ const newCircuit = circuits.get(key);
399
+ if (!newCircuit) {
400
+ return;
401
+ }
402
+ transitionState(newCircuit, 'open', `Forced open: ${reason}`);
403
+ return;
404
+ }
405
+
406
+ transitionState(circuit, 'open', `Forced open: ${reason}`);
407
+
408
+ Logger.warn(`Circuit breaker forced open: ${key}`, { reason });
409
+ },
410
+
411
+ /**
412
+ * Delete circuit breaker
413
+ */
414
+ delete(workerName: string, version: string): void {
415
+ const key = getCircuitKey(workerName, version);
416
+ circuits.delete(key);
417
+ eventHistory.delete(key);
418
+
419
+ Logger.info(`Circuit breaker deleted: ${key}`);
420
+ },
421
+
422
+ /**
423
+ * Delete all circuit breakers for a worker (all versions)
424
+ */
425
+ deleteWorker(workerName: string): void {
426
+ const keysToDelete: string[] = [];
427
+
428
+ for (const [key, circuit] of circuits.entries()) {
429
+ if (circuit.workerName === workerName) {
430
+ keysToDelete.push(key);
431
+ }
432
+ }
433
+
434
+ for (const key of keysToDelete) {
435
+ circuits.delete(key);
436
+ eventHistory.delete(key);
437
+ }
438
+
439
+ Logger.info(`Deleted all circuit breakers for worker: ${workerName}`, {
440
+ count: keysToDelete.length,
441
+ });
442
+ },
443
+
444
+ /**
445
+ * Get summary statistics
446
+ */
447
+ getSummary(): {
448
+ totalCircuits: number;
449
+ openCircuits: number;
450
+ halfOpenCircuits: number;
451
+ closedCircuits: number;
452
+ circuitsByWorker: Record<string, number>;
453
+ } {
454
+ const summary = {
455
+ totalCircuits: circuits.size,
456
+ openCircuits: 0,
457
+ halfOpenCircuits: 0,
458
+ closedCircuits: 0,
459
+ circuitsByWorker: {} as Record<string, number>,
460
+ };
461
+
462
+ for (const circuit of circuits.values()) {
463
+ switch (circuit.state) {
464
+ case 'open':
465
+ summary.openCircuits++;
466
+ break;
467
+ case 'half-open':
468
+ summary.halfOpenCircuits++;
469
+ break;
470
+ case 'closed':
471
+ summary.closedCircuits++;
472
+ break;
473
+ }
474
+
475
+ summary.circuitsByWorker[circuit.workerName] =
476
+ (summary.circuitsByWorker[circuit.workerName] || 0) + 1;
477
+ }
478
+
479
+ return summary;
480
+ },
481
+
482
+ /**
483
+ * Shutdown and clear all circuits
484
+ */
485
+ shutdown(): void {
486
+ Logger.info('CircuitBreaker shutting down...');
487
+
488
+ circuits.clear();
489
+ eventHistory.clear();
490
+
491
+ Logger.info('CircuitBreaker shutdown complete');
492
+ },
493
+ });
494
+
495
+ // Graceful shutdown handled by WorkerShutdown