@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,106 @@
1
+ /**
2
+ * Circuit Breaker Pattern
3
+ * Fault tolerance with version tracking and automatic recovery
4
+ * Sealed namespace for immutability
5
+ */
6
+ export type CircuitState = 'closed' | 'open' | 'half-open';
7
+ export type CircuitBreakerConfig = {
8
+ failureThreshold: number;
9
+ successThreshold: number;
10
+ timeout: number;
11
+ resetTimeout: number;
12
+ volumeThreshold: number;
13
+ };
14
+ export type CircuitBreakerState = {
15
+ workerName: string;
16
+ version: string;
17
+ state: CircuitState;
18
+ failureCount: number;
19
+ successCount: number;
20
+ totalRequests: number;
21
+ lastFailureTime: Date | null;
22
+ lastSuccessTime: Date | null;
23
+ lastStateChange: Date;
24
+ nextRetryTime: Date | null;
25
+ errorRate: number;
26
+ };
27
+ export type CircuitBreakerEvent = {
28
+ workerName: string;
29
+ version: string;
30
+ event: 'opened' | 'closed' | 'half-open' | 'success' | 'failure' | 'rejected';
31
+ state: CircuitState;
32
+ timestamp: Date;
33
+ reason?: string;
34
+ error?: Error;
35
+ };
36
+ /**
37
+ * Circuit Breaker - Sealed namespace
38
+ */
39
+ export declare const CircuitBreaker: Readonly<{
40
+ /**
41
+ * Initialize circuit breaker for a worker version
42
+ */
43
+ initialize(workerName: string, version: string): void;
44
+ /**
45
+ * Check if circuit allows execution
46
+ */
47
+ canExecute(workerName: string, version: string): boolean;
48
+ /**
49
+ * Record successful execution
50
+ */
51
+ recordSuccess(workerName: string, version: string): void;
52
+ /**
53
+ * Record failed execution
54
+ */
55
+ recordFailure(workerName: string, version: string, error: Error): void;
56
+ /**
57
+ * Record rejected execution (when circuit is open)
58
+ */
59
+ recordRejection(workerName: string, version: string): void;
60
+ /**
61
+ * Get circuit state
62
+ */
63
+ getState(workerName: string, version: string): CircuitBreakerState | null;
64
+ /**
65
+ * Get all circuit states
66
+ */
67
+ getAllStates(): ReadonlyArray<CircuitBreakerState>;
68
+ /**
69
+ * Get circuit states by worker name (all versions)
70
+ */
71
+ getStatesByWorker(workerName: string): ReadonlyArray<CircuitBreakerState>;
72
+ /**
73
+ * Get event history
74
+ */
75
+ getEventHistory(workerName: string, version: string, limit?: number): ReadonlyArray<CircuitBreakerEvent>;
76
+ /**
77
+ * Manually reset circuit to closed state
78
+ */
79
+ reset(workerName: string, version: string): void;
80
+ /**
81
+ * Manually force circuit to open state
82
+ */
83
+ forceOpen(workerName: string, version: string, reason: string): void;
84
+ /**
85
+ * Delete circuit breaker
86
+ */
87
+ delete(workerName: string, version: string): void;
88
+ /**
89
+ * Delete all circuit breakers for a worker (all versions)
90
+ */
91
+ deleteWorker(workerName: string): void;
92
+ /**
93
+ * Get summary statistics
94
+ */
95
+ getSummary(): {
96
+ totalCircuits: number;
97
+ openCircuits: number;
98
+ halfOpenCircuits: number;
99
+ closedCircuits: number;
100
+ circuitsByWorker: Record<string, number>;
101
+ };
102
+ /**
103
+ * Shutdown and clear all circuits
104
+ */
105
+ shutdown(): void;
106
+ }>;
@@ -0,0 +1,374 @@
1
+ /**
2
+ * Circuit Breaker Pattern
3
+ * Fault tolerance with version tracking and automatic recovery
4
+ * Sealed namespace for immutability
5
+ */
6
+ import { Logger } from '@zintrust/core';
7
+ // Internal state
8
+ const circuits = new Map();
9
+ const eventHistory = new Map();
10
+ const defaultConfig = {
11
+ failureThreshold: 5,
12
+ successThreshold: 3,
13
+ timeout: 60000, // 1 minute
14
+ resetTimeout: 300000, // 5 minutes
15
+ volumeThreshold: 10,
16
+ };
17
+ /**
18
+ * Helper: Get circuit key
19
+ */
20
+ const getCircuitKey = (workerName, version) => {
21
+ return `${workerName}:${version}`;
22
+ };
23
+ /**
24
+ * Helper: Record event
25
+ */
26
+ const recordEvent = (event) => {
27
+ const key = getCircuitKey(event.workerName, event.version);
28
+ let history = eventHistory.get(key);
29
+ if (!history) {
30
+ history = [];
31
+ eventHistory.set(key, history);
32
+ }
33
+ history.push(event);
34
+ // Keep only last 1000 events
35
+ if (history.length > 1000) {
36
+ history.shift();
37
+ }
38
+ Logger.debug(`Circuit breaker event: ${event.workerName}:${event.version} - ${event.event}`, {
39
+ state: event.state,
40
+ reason: event.reason,
41
+ });
42
+ };
43
+ /**
44
+ * Helper: Transition to new state
45
+ */
46
+ const transitionState = (circuit, newState, reason) => {
47
+ const oldState = circuit.state;
48
+ circuit.state = newState;
49
+ circuit.lastStateChange = new Date();
50
+ if (newState === 'open') {
51
+ circuit.nextRetryTime = new Date(Date.now() + defaultConfig.timeout);
52
+ }
53
+ else if (newState === 'closed') {
54
+ circuit.failureCount = 0;
55
+ circuit.successCount = 0;
56
+ circuit.nextRetryTime = null;
57
+ }
58
+ else if (newState === 'half-open') {
59
+ circuit.successCount = 0;
60
+ circuit.nextRetryTime = null;
61
+ }
62
+ Logger.info(`Circuit breaker state transition: ${circuit.workerName}:${circuit.version}`, {
63
+ from: oldState,
64
+ to: newState,
65
+ reason,
66
+ });
67
+ const eventType = newState === 'open' ? 'opened' : newState;
68
+ recordEvent({
69
+ workerName: circuit.workerName,
70
+ version: circuit.version,
71
+ event: eventType,
72
+ state: newState,
73
+ timestamp: new Date(),
74
+ reason,
75
+ });
76
+ };
77
+ /**
78
+ * Helper: Calculate error rate
79
+ */
80
+ const calculateErrorRate = (circuit) => {
81
+ if (circuit.totalRequests === 0) {
82
+ return 0;
83
+ }
84
+ return (circuit.failureCount / circuit.totalRequests) * 100;
85
+ };
86
+ /**
87
+ * Helper: Check if should reset failure count
88
+ */
89
+ const shouldResetFailureCount = (circuit) => {
90
+ if (!circuit.lastFailureTime) {
91
+ return false;
92
+ }
93
+ const timeSinceLastFailure = Date.now() - circuit.lastFailureTime.getTime();
94
+ return timeSinceLastFailure > defaultConfig.resetTimeout;
95
+ };
96
+ /**
97
+ * Circuit Breaker - Sealed namespace
98
+ */
99
+ export const CircuitBreaker = Object.freeze({
100
+ /**
101
+ * Initialize circuit breaker for a worker version
102
+ */
103
+ initialize(workerName, version) {
104
+ const key = getCircuitKey(workerName, version);
105
+ if (circuits.has(key)) {
106
+ Logger.debug(`Circuit breaker already exists: ${key}`);
107
+ return;
108
+ }
109
+ const circuit = {
110
+ workerName,
111
+ version,
112
+ state: 'closed',
113
+ failureCount: 0,
114
+ successCount: 0,
115
+ totalRequests: 0,
116
+ lastFailureTime: null,
117
+ lastSuccessTime: null,
118
+ lastStateChange: new Date(),
119
+ nextRetryTime: null,
120
+ errorRate: 0,
121
+ };
122
+ circuits.set(key, circuit);
123
+ Logger.info(`Circuit breaker initialized: ${key}`);
124
+ },
125
+ /**
126
+ * Check if circuit allows execution
127
+ */
128
+ canExecute(workerName, version) {
129
+ const key = getCircuitKey(workerName, version);
130
+ const circuit = circuits.get(key);
131
+ if (!circuit) {
132
+ // No circuit exists, create and allow
133
+ CircuitBreaker.initialize(workerName, version);
134
+ return true;
135
+ }
136
+ const now = Date.now();
137
+ // Reset failure count if enough time has passed
138
+ if (circuit.state === 'closed' && shouldResetFailureCount(circuit)) {
139
+ circuit.failureCount = 0;
140
+ circuit.totalRequests = 0;
141
+ Logger.debug(`Reset failure count for ${key}`);
142
+ }
143
+ switch (circuit.state) {
144
+ case 'closed':
145
+ return true;
146
+ case 'open':
147
+ // Check if timeout has passed to try half-open
148
+ if (circuit.nextRetryTime && now >= circuit.nextRetryTime.getTime()) {
149
+ transitionState(circuit, 'half-open', 'Timeout elapsed, attempting recovery');
150
+ return true;
151
+ }
152
+ return false;
153
+ case 'half-open':
154
+ // Allow limited requests to test recovery
155
+ return true;
156
+ }
157
+ },
158
+ /**
159
+ * Record successful execution
160
+ */
161
+ recordSuccess(workerName, version) {
162
+ const key = getCircuitKey(workerName, version);
163
+ const circuit = circuits.get(key);
164
+ if (!circuit) {
165
+ CircuitBreaker.initialize(workerName, version);
166
+ return;
167
+ }
168
+ circuit.successCount++;
169
+ circuit.totalRequests++;
170
+ circuit.lastSuccessTime = new Date();
171
+ circuit.errorRate = calculateErrorRate(circuit);
172
+ recordEvent({
173
+ workerName,
174
+ version,
175
+ event: 'success',
176
+ state: circuit.state,
177
+ timestamp: new Date(),
178
+ });
179
+ // Transition based on state
180
+ if (circuit.state === 'half-open') {
181
+ if (circuit.successCount >= defaultConfig.successThreshold) {
182
+ transitionState(circuit, 'closed', `${circuit.successCount} consecutive successes`);
183
+ }
184
+ }
185
+ },
186
+ /**
187
+ * Record failed execution
188
+ */
189
+ recordFailure(workerName, version, error) {
190
+ const key = getCircuitKey(workerName, version);
191
+ const circuit = circuits.get(key);
192
+ if (!circuit) {
193
+ CircuitBreaker.initialize(workerName, version);
194
+ return;
195
+ }
196
+ circuit.failureCount++;
197
+ circuit.totalRequests++;
198
+ circuit.lastFailureTime = new Date();
199
+ circuit.errorRate = calculateErrorRate(circuit);
200
+ recordEvent({
201
+ workerName,
202
+ version,
203
+ event: 'failure',
204
+ state: circuit.state,
205
+ timestamp: new Date(),
206
+ error,
207
+ });
208
+ // Transition based on state and thresholds
209
+ if (circuit.state === 'half-open') {
210
+ // Any failure in half-open reopens the circuit
211
+ transitionState(circuit, 'open', 'Failure during recovery attempt');
212
+ }
213
+ else if (circuit.state === 'closed') {
214
+ // Check if should open based on failure threshold
215
+ if (circuit.totalRequests >= defaultConfig.volumeThreshold) {
216
+ if (circuit.failureCount >= defaultConfig.failureThreshold) {
217
+ transitionState(circuit, 'open', `Failure threshold exceeded: ${circuit.failureCount}/${defaultConfig.failureThreshold}`);
218
+ }
219
+ }
220
+ }
221
+ },
222
+ /**
223
+ * Record rejected execution (when circuit is open)
224
+ */
225
+ recordRejection(workerName, version) {
226
+ const key = getCircuitKey(workerName, version);
227
+ const circuit = circuits.get(key);
228
+ if (!circuit) {
229
+ return;
230
+ }
231
+ recordEvent({
232
+ workerName,
233
+ version,
234
+ event: 'rejected',
235
+ state: circuit.state,
236
+ timestamp: new Date(),
237
+ reason: 'Circuit breaker is open',
238
+ });
239
+ },
240
+ /**
241
+ * Get circuit state
242
+ */
243
+ getState(workerName, version) {
244
+ const key = getCircuitKey(workerName, version);
245
+ const circuit = circuits.get(key);
246
+ return circuit ? { ...circuit } : null;
247
+ },
248
+ /**
249
+ * Get all circuit states
250
+ */
251
+ getAllStates() {
252
+ return Array.from(circuits.values()).map((circuit) => ({ ...circuit }));
253
+ },
254
+ /**
255
+ * Get circuit states by worker name (all versions)
256
+ */
257
+ getStatesByWorker(workerName) {
258
+ const states = [];
259
+ for (const circuit of circuits.values()) {
260
+ if (circuit.workerName === workerName) {
261
+ states.push({ ...circuit });
262
+ }
263
+ }
264
+ return states;
265
+ },
266
+ /**
267
+ * Get event history
268
+ */
269
+ getEventHistory(workerName, version, limit = 100) {
270
+ const key = getCircuitKey(workerName, version);
271
+ const history = eventHistory.get(key) ?? [];
272
+ return history.slice(-limit).map((event) => ({ ...event }));
273
+ },
274
+ /**
275
+ * Manually reset circuit to closed state
276
+ */
277
+ reset(workerName, version) {
278
+ const key = getCircuitKey(workerName, version);
279
+ const circuit = circuits.get(key);
280
+ if (!circuit) {
281
+ Logger.warn(`Circuit breaker not found: ${key}`);
282
+ return;
283
+ }
284
+ transitionState(circuit, 'closed', 'Manual reset');
285
+ circuit.failureCount = 0;
286
+ circuit.successCount = 0;
287
+ circuit.totalRequests = 0;
288
+ circuit.errorRate = 0;
289
+ Logger.info(`Circuit breaker manually reset: ${key}`);
290
+ },
291
+ /**
292
+ * Manually force circuit to open state
293
+ */
294
+ forceOpen(workerName, version, reason) {
295
+ const key = getCircuitKey(workerName, version);
296
+ const circuit = circuits.get(key);
297
+ if (!circuit) {
298
+ CircuitBreaker.initialize(workerName, version);
299
+ const newCircuit = circuits.get(key);
300
+ if (!newCircuit) {
301
+ return;
302
+ }
303
+ transitionState(newCircuit, 'open', `Forced open: ${reason}`);
304
+ return;
305
+ }
306
+ transitionState(circuit, 'open', `Forced open: ${reason}`);
307
+ Logger.warn(`Circuit breaker forced open: ${key}`, { reason });
308
+ },
309
+ /**
310
+ * Delete circuit breaker
311
+ */
312
+ delete(workerName, version) {
313
+ const key = getCircuitKey(workerName, version);
314
+ circuits.delete(key);
315
+ eventHistory.delete(key);
316
+ Logger.info(`Circuit breaker deleted: ${key}`);
317
+ },
318
+ /**
319
+ * Delete all circuit breakers for a worker (all versions)
320
+ */
321
+ deleteWorker(workerName) {
322
+ const keysToDelete = [];
323
+ for (const [key, circuit] of circuits.entries()) {
324
+ if (circuit.workerName === workerName) {
325
+ keysToDelete.push(key);
326
+ }
327
+ }
328
+ for (const key of keysToDelete) {
329
+ circuits.delete(key);
330
+ eventHistory.delete(key);
331
+ }
332
+ Logger.info(`Deleted all circuit breakers for worker: ${workerName}`, {
333
+ count: keysToDelete.length,
334
+ });
335
+ },
336
+ /**
337
+ * Get summary statistics
338
+ */
339
+ getSummary() {
340
+ const summary = {
341
+ totalCircuits: circuits.size,
342
+ openCircuits: 0,
343
+ halfOpenCircuits: 0,
344
+ closedCircuits: 0,
345
+ circuitsByWorker: {},
346
+ };
347
+ for (const circuit of circuits.values()) {
348
+ switch (circuit.state) {
349
+ case 'open':
350
+ summary.openCircuits++;
351
+ break;
352
+ case 'half-open':
353
+ summary.halfOpenCircuits++;
354
+ break;
355
+ case 'closed':
356
+ summary.closedCircuits++;
357
+ break;
358
+ }
359
+ summary.circuitsByWorker[circuit.workerName] =
360
+ (summary.circuitsByWorker[circuit.workerName] || 0) + 1;
361
+ }
362
+ return summary;
363
+ },
364
+ /**
365
+ * Shutdown and clear all circuits
366
+ */
367
+ shutdown() {
368
+ Logger.info('CircuitBreaker shutting down...');
369
+ circuits.clear();
370
+ eventHistory.clear();
371
+ Logger.info('CircuitBreaker shutdown complete');
372
+ },
373
+ });
374
+ // Graceful shutdown handled by WorkerShutdown
@@ -0,0 +1,90 @@
1
+ /**
2
+ * Cluster Lock Manager
3
+ * Distributed locking using Redis for multi-instance worker coordination
4
+ * Sealed namespace for immutability
5
+ */
6
+ import { type RedisConfig } from '@zintrust/core';
7
+ export type LockAcquisitionOptions = {
8
+ lockKey: string;
9
+ ttl: number;
10
+ region?: string;
11
+ userId?: string;
12
+ };
13
+ export type LockInfo = {
14
+ lockKey: string;
15
+ instanceId: string;
16
+ acquiredAt: Date;
17
+ expiresAt: Date;
18
+ region: string;
19
+ userId?: string;
20
+ };
21
+ export type AuditLogEntry = {
22
+ timestamp: Date;
23
+ operation: 'acquire' | 'release' | 'extend' | 'force-release';
24
+ lockKey: string;
25
+ instanceId: string;
26
+ userId?: string;
27
+ reason?: string;
28
+ success: boolean;
29
+ };
30
+ /**
31
+ * Cluster Lock Manager - Sealed namespace
32
+ */
33
+ export declare const ClusterLock: Readonly<{
34
+ /**
35
+ * Initialize the lock manager with Redis connection
36
+ */
37
+ initialize(config: RedisConfig): void;
38
+ /**
39
+ * Acquire a distributed lock
40
+ */
41
+ acquire(options: LockAcquisitionOptions): Promise<boolean>;
42
+ /**
43
+ * Release a distributed lock
44
+ */
45
+ release(lockKey: string, userId?: string): Promise<boolean>;
46
+ /**
47
+ * Extend lock TTL
48
+ */
49
+ extend(lockKey: string, ttl: number): Promise<boolean>;
50
+ /**
51
+ * Check if lock is held by this instance
52
+ */
53
+ isHeldByMe(lockKey: string): Promise<boolean>;
54
+ /**
55
+ * Force release a lock (admin operation)
56
+ */
57
+ forceRelease(lockKey: string, userId: string, reason: string): Promise<boolean>;
58
+ /**
59
+ * List all locks
60
+ */
61
+ listLocks(): Promise<ReadonlyArray<{
62
+ key: string;
63
+ owner: string;
64
+ region?: string;
65
+ }>>;
66
+ /**
67
+ * Get lock owner
68
+ */
69
+ getLockOwner(lockKey: string): Promise<string | null>;
70
+ /**
71
+ * Get locks by region
72
+ */
73
+ getLocksByRegion(region: string): ReadonlyArray<LockInfo>;
74
+ /**
75
+ * Get audit log for a lock
76
+ */
77
+ getAuditLog(lockKey: string, limit?: number): Promise<ReadonlyArray<AuditLogEntry>>;
78
+ /**
79
+ * Get active locks held by this instance
80
+ */
81
+ getActiveLocks(): ReadonlyArray<LockInfo>;
82
+ /**
83
+ * Get instance ID
84
+ */
85
+ getInstanceId(): string;
86
+ /**
87
+ * Shutdown and release all locks
88
+ */
89
+ shutdown(): Promise<void>;
90
+ }>;