canxjs 1.6.1 → 1.6.2
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.
- package/dist/src/core/CircuitBreaker.d.ts +121 -0
- package/dist/src/core/CircuitBreaker.d.ts.map +1 -0
- package/dist/src/core/CircuitBreaker.js +250 -0
- package/dist/src/core/ClusterManager.d.ts +122 -0
- package/dist/src/core/ClusterManager.d.ts.map +1 -0
- package/dist/src/core/ClusterManager.js +280 -0
- package/dist/src/core/DistributedSession.d.ts +109 -0
- package/dist/src/core/DistributedSession.d.ts.map +1 -0
- package/dist/src/core/DistributedSession.js +241 -0
- package/dist/src/core/GracefulShutdown.d.ts +87 -0
- package/dist/src/core/GracefulShutdown.d.ts.map +1 -0
- package/dist/src/core/GracefulShutdown.js +192 -0
- package/dist/src/core/HealthChecks.d.ts +155 -0
- package/dist/src/core/HealthChecks.d.ts.map +1 -0
- package/dist/src/core/HealthChecks.js +362 -0
- package/dist/src/core/RateLimiterV2.d.ts +122 -0
- package/dist/src/core/RateLimiterV2.d.ts.map +1 -0
- package/dist/src/core/RateLimiterV2.js +261 -0
- package/dist/src/flow/Workflow.d.ts +91 -0
- package/dist/src/flow/Workflow.d.ts.map +1 -0
- package/dist/src/flow/Workflow.js +213 -0
- package/dist/src/index.d.ts +35 -23
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +60 -46
- package/dist/src/microservices/EventBus.d.ts +116 -0
- package/dist/src/microservices/EventBus.d.ts.map +1 -0
- package/dist/src/microservices/EventBus.js +274 -0
- package/dist/src/microservices/ServiceRegistry.d.ts +138 -0
- package/dist/src/microservices/ServiceRegistry.d.ts.map +1 -0
- package/dist/src/microservices/ServiceRegistry.js +351 -0
- package/dist/src/observability/Metrics.d.ts +74 -0
- package/dist/src/observability/Metrics.d.ts.map +1 -0
- package/dist/src/observability/Metrics.js +199 -0
- package/dist/src/observability/Tracing.d.ts +89 -0
- package/dist/src/observability/Tracing.d.ts.map +1 -0
- package/dist/src/observability/Tracing.js +154 -0
- package/dist/src/security/AuditLogger.d.ts +80 -0
- package/dist/src/security/AuditLogger.d.ts.map +1 -0
- package/dist/src/security/AuditLogger.js +139 -0
- package/dist/src/security/OAuth2Provider.d.ts +78 -0
- package/dist/src/security/OAuth2Provider.d.ts.map +1 -0
- package/dist/src/security/OAuth2Provider.js +142 -0
- package/dist/src/security/SecretsManager.d.ts +44 -0
- package/dist/src/security/SecretsManager.d.ts.map +1 -0
- package/dist/src/security/SecretsManager.js +74 -0
- package/dist/src/universal/Signal.d.ts +54 -0
- package/dist/src/universal/Signal.d.ts.map +1 -0
- package/dist/src/universal/Signal.js +142 -0
- package/dist/src/universal/SignalRegistry.d.ts +29 -0
- package/dist/src/universal/SignalRegistry.d.ts.map +1 -0
- package/dist/src/universal/SignalRegistry.js +48 -0
- package/dist/src/universal/SignalServer.d.ts +25 -0
- package/dist/src/universal/SignalServer.d.ts.map +1 -0
- package/dist/src/universal/SignalServer.js +78 -0
- package/package.json +1 -1
- package/src/core/CircuitBreaker.ts +322 -0
- package/src/core/ClusterManager.ts +365 -0
- package/src/core/DistributedSession.ts +315 -0
- package/src/core/GracefulShutdown.ts +235 -0
- package/src/core/HealthChecks.ts +469 -0
- package/src/core/RateLimiterV2.ts +361 -0
- package/src/flow/Workflow.ts +272 -0
- package/src/index.ts +252 -140
- package/src/microservices/EventBus.ts +362 -0
- package/src/microservices/ServiceRegistry.ts +435 -0
- package/src/observability/Metrics.ts +265 -0
- package/src/observability/Tracing.ts +211 -0
- package/src/security/AuditLogger.ts +208 -0
- package/src/security/OAuth2Provider.ts +201 -0
- package/src/security/SecretsManager.ts +94 -0
- package/src/universal/Signal.ts +165 -0
- package/src/universal/SignalRegistry.ts +57 -0
- package/src/universal/SignalServer.ts +94 -0
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CanxJS Circuit Breaker - Fault tolerance for external services
|
|
3
|
+
* @description Prevents cascading failures by detecting failures and short-circuiting requests
|
|
4
|
+
*/
|
|
5
|
+
export type CircuitState = 'CLOSED' | 'OPEN' | 'HALF_OPEN';
|
|
6
|
+
export interface CircuitBreakerConfig {
|
|
7
|
+
/** Name for logging/metrics */
|
|
8
|
+
name?: string;
|
|
9
|
+
/** Number of failures before opening circuit */
|
|
10
|
+
failureThreshold?: number;
|
|
11
|
+
/** Number of successes in half-open to close circuit */
|
|
12
|
+
successThreshold?: number;
|
|
13
|
+
/** Time in ms before attempting half-open */
|
|
14
|
+
timeout?: number;
|
|
15
|
+
/** Sliding window size in ms for failure counting */
|
|
16
|
+
windowSize?: number;
|
|
17
|
+
/** Custom failure detector */
|
|
18
|
+
isFailure?: (error: unknown) => boolean;
|
|
19
|
+
/** Fallback function when circuit is open */
|
|
20
|
+
fallback?: <T>() => T | Promise<T>;
|
|
21
|
+
/** Enable metrics collection */
|
|
22
|
+
metrics?: boolean;
|
|
23
|
+
}
|
|
24
|
+
interface CircuitMetrics {
|
|
25
|
+
totalRequests: number;
|
|
26
|
+
successfulRequests: number;
|
|
27
|
+
failedRequests: number;
|
|
28
|
+
rejectedRequests: number;
|
|
29
|
+
lastFailureTime?: Date;
|
|
30
|
+
lastSuccessTime?: Date;
|
|
31
|
+
stateChanges: {
|
|
32
|
+
state: CircuitState;
|
|
33
|
+
timestamp: Date;
|
|
34
|
+
}[];
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Circuit Breaker implementation
|
|
38
|
+
* Implements the circuit breaker pattern for fault tolerance
|
|
39
|
+
*/
|
|
40
|
+
export declare class CircuitBreaker {
|
|
41
|
+
private config;
|
|
42
|
+
private state;
|
|
43
|
+
private failures;
|
|
44
|
+
private successCount;
|
|
45
|
+
private lastStateChange;
|
|
46
|
+
private metrics;
|
|
47
|
+
constructor(config?: CircuitBreakerConfig);
|
|
48
|
+
/**
|
|
49
|
+
* Get current circuit state
|
|
50
|
+
*/
|
|
51
|
+
getState(): CircuitState;
|
|
52
|
+
/**
|
|
53
|
+
* Get circuit metrics
|
|
54
|
+
*/
|
|
55
|
+
getMetrics(): CircuitMetrics;
|
|
56
|
+
/**
|
|
57
|
+
* Check if circuit is allowing requests
|
|
58
|
+
*/
|
|
59
|
+
isAllowed(): boolean;
|
|
60
|
+
/**
|
|
61
|
+
* Execute function with circuit breaker protection
|
|
62
|
+
*/
|
|
63
|
+
execute<T>(fn: () => Promise<T>): Promise<T>;
|
|
64
|
+
/**
|
|
65
|
+
* Record a successful call
|
|
66
|
+
*/
|
|
67
|
+
private onSuccess;
|
|
68
|
+
/**
|
|
69
|
+
* Record a failed call
|
|
70
|
+
*/
|
|
71
|
+
private onFailure;
|
|
72
|
+
/**
|
|
73
|
+
* Transition to a new state
|
|
74
|
+
*/
|
|
75
|
+
private transitionTo;
|
|
76
|
+
/**
|
|
77
|
+
* Remove failures outside the sliding window
|
|
78
|
+
*/
|
|
79
|
+
private cleanupOldFailures;
|
|
80
|
+
/**
|
|
81
|
+
* Force circuit to open
|
|
82
|
+
*/
|
|
83
|
+
forceOpen(): void;
|
|
84
|
+
/**
|
|
85
|
+
* Force circuit to close
|
|
86
|
+
*/
|
|
87
|
+
forceClose(): void;
|
|
88
|
+
/**
|
|
89
|
+
* Reset circuit to initial state
|
|
90
|
+
*/
|
|
91
|
+
reset(): void;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Circuit Breaker Error
|
|
95
|
+
*/
|
|
96
|
+
export declare class CircuitBreakerError extends Error {
|
|
97
|
+
readonly circuitName: string;
|
|
98
|
+
readonly circuitState: CircuitState;
|
|
99
|
+
constructor(message: string, circuitName: string, circuitState: CircuitState);
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Get or create a circuit breaker
|
|
103
|
+
*/
|
|
104
|
+
export declare function getCircuitBreaker(name: string, config?: CircuitBreakerConfig): CircuitBreaker;
|
|
105
|
+
/**
|
|
106
|
+
* Create a new circuit breaker
|
|
107
|
+
*/
|
|
108
|
+
export declare function createCircuitBreaker(config?: CircuitBreakerConfig): CircuitBreaker;
|
|
109
|
+
/**
|
|
110
|
+
* Get all circuit breaker statuses
|
|
111
|
+
*/
|
|
112
|
+
export declare function getCircuitBreakerStatus(): Record<string, {
|
|
113
|
+
state: CircuitState;
|
|
114
|
+
metrics: CircuitMetrics;
|
|
115
|
+
}>;
|
|
116
|
+
/**
|
|
117
|
+
* Decorator for circuit breaker
|
|
118
|
+
*/
|
|
119
|
+
export declare function WithCircuitBreaker(nameOrConfig: string | CircuitBreakerConfig): (target: any, propertyKey: string, descriptor: PropertyDescriptor) => PropertyDescriptor;
|
|
120
|
+
export default CircuitBreaker;
|
|
121
|
+
//# sourceMappingURL=CircuitBreaker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CircuitBreaker.d.ts","sourceRoot":"","sources":["../../../src/core/CircuitBreaker.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,MAAM,YAAY,GAAG,QAAQ,GAAG,MAAM,GAAG,WAAW,CAAC;AAE3D,MAAM,WAAW,oBAAoB;IACnC,+BAA+B;IAC/B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,gDAAgD;IAChD,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,wDAAwD;IACxD,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,6CAA6C;IAC7C,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,qDAAqD;IACrD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,8BAA8B;IAC9B,SAAS,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,OAAO,CAAC;IACxC,6CAA6C;IAC7C,QAAQ,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;IACnC,gCAAgC;IAChC,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,UAAU,cAAc;IACtB,aAAa,EAAE,MAAM,CAAC;IACtB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,cAAc,EAAE,MAAM,CAAC;IACvB,gBAAgB,EAAE,MAAM,CAAC;IACzB,eAAe,CAAC,EAAE,IAAI,CAAC;IACvB,eAAe,CAAC,EAAE,IAAI,CAAC;IACvB,YAAY,EAAE;QAAE,KAAK,EAAE,YAAY,CAAC;QAAC,SAAS,EAAE,IAAI,CAAA;KAAE,EAAE,CAAC;CAC1D;AAOD;;;GAGG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,MAAM,CAAqG;IACnH,OAAO,CAAC,KAAK,CAA0B;IACvC,OAAO,CAAC,QAAQ,CAAuB;IACvC,OAAO,CAAC,YAAY,CAAK;IACzB,OAAO,CAAC,eAAe,CAAoB;IAC3C,OAAO,CAAC,OAAO,CAAiB;gBAEpB,MAAM,GAAE,oBAAyB;IAqB7C;;OAEG;IACH,QAAQ,IAAI,YAAY;IAIxB;;OAEG;IACH,UAAU,IAAI,cAAc;IAI5B;;OAEG;IACH,SAAS,IAAI,OAAO;IAiBpB;;OAEG;IACG,OAAO,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IA+BlD;;OAEG;IACH,OAAO,CAAC,SAAS;IAkBjB;;OAEG;IACH,OAAO,CAAC,SAAS;IAuBjB;;OAEG;IACH,OAAO,CAAC,YAAY;IAiBpB;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAK1B;;OAEG;IACH,SAAS,IAAI,IAAI;IAIjB;;OAEG;IACH,UAAU,IAAI,IAAI;IAIlB;;OAEG;IACH,KAAK,IAAI,IAAI;CAad;AAED;;GAEG;AACH,qBAAa,mBAAoB,SAAQ,KAAK;aAG1B,WAAW,EAAE,MAAM;aACnB,YAAY,EAAE,YAAY;gBAF1C,OAAO,EAAE,MAAM,EACC,WAAW,EAAE,MAAM,EACnB,YAAY,EAAE,YAAY;CAK7C;AAQD;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,oBAAoB,GAAG,cAAc,CAK7F;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,GAAE,oBAAyB,GAAG,cAAc,CAMtF;AAED;;GAEG;AACH,wBAAgB,uBAAuB,IAAI,MAAM,CAAC,MAAM,EAAE;IAAE,KAAK,EAAE,YAAY,CAAC;IAAC,OAAO,EAAE,cAAc,CAAA;CAAE,CAAC,CAS1G;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,YAAY,EAAE,MAAM,GAAG,oBAAoB,IAC3D,QAAQ,GAAG,EAAE,aAAa,MAAM,EAAE,YAAY,kBAAkB,wBAWlF;AAED,eAAe,cAAc,CAAC"}
|
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CanxJS Circuit Breaker - Fault tolerance for external services
|
|
3
|
+
* @description Prevents cascading failures by detecting failures and short-circuiting requests
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Circuit Breaker implementation
|
|
7
|
+
* Implements the circuit breaker pattern for fault tolerance
|
|
8
|
+
*/
|
|
9
|
+
export class CircuitBreaker {
|
|
10
|
+
config;
|
|
11
|
+
state = 'CLOSED';
|
|
12
|
+
failures = [];
|
|
13
|
+
successCount = 0;
|
|
14
|
+
lastStateChange = new Date();
|
|
15
|
+
metrics;
|
|
16
|
+
constructor(config = {}) {
|
|
17
|
+
this.config = {
|
|
18
|
+
name: config.name ?? 'default',
|
|
19
|
+
failureThreshold: config.failureThreshold ?? 5,
|
|
20
|
+
successThreshold: config.successThreshold ?? 2,
|
|
21
|
+
timeout: config.timeout ?? 30000,
|
|
22
|
+
windowSize: config.windowSize ?? 60000,
|
|
23
|
+
isFailure: config.isFailure ?? (() => true),
|
|
24
|
+
metrics: config.metrics ?? true,
|
|
25
|
+
fallback: config.fallback,
|
|
26
|
+
};
|
|
27
|
+
this.metrics = {
|
|
28
|
+
totalRequests: 0,
|
|
29
|
+
successfulRequests: 0,
|
|
30
|
+
failedRequests: 0,
|
|
31
|
+
rejectedRequests: 0,
|
|
32
|
+
stateChanges: [{ state: 'CLOSED', timestamp: new Date() }],
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Get current circuit state
|
|
37
|
+
*/
|
|
38
|
+
getState() {
|
|
39
|
+
return this.state;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Get circuit metrics
|
|
43
|
+
*/
|
|
44
|
+
getMetrics() {
|
|
45
|
+
return { ...this.metrics };
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Check if circuit is allowing requests
|
|
49
|
+
*/
|
|
50
|
+
isAllowed() {
|
|
51
|
+
this.cleanupOldFailures();
|
|
52
|
+
switch (this.state) {
|
|
53
|
+
case 'CLOSED':
|
|
54
|
+
return true;
|
|
55
|
+
case 'OPEN':
|
|
56
|
+
if (Date.now() - this.lastStateChange.getTime() >= this.config.timeout) {
|
|
57
|
+
this.transitionTo('HALF_OPEN');
|
|
58
|
+
return true;
|
|
59
|
+
}
|
|
60
|
+
return false;
|
|
61
|
+
case 'HALF_OPEN':
|
|
62
|
+
return true;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Execute function with circuit breaker protection
|
|
67
|
+
*/
|
|
68
|
+
async execute(fn) {
|
|
69
|
+
this.metrics.totalRequests++;
|
|
70
|
+
if (!this.isAllowed()) {
|
|
71
|
+
this.metrics.rejectedRequests++;
|
|
72
|
+
if (this.config.fallback) {
|
|
73
|
+
return this.config.fallback();
|
|
74
|
+
}
|
|
75
|
+
throw new CircuitBreakerError(`Circuit breaker '${this.config.name}' is OPEN`, this.config.name, this.state);
|
|
76
|
+
}
|
|
77
|
+
try {
|
|
78
|
+
const result = await fn();
|
|
79
|
+
this.onSuccess();
|
|
80
|
+
return result;
|
|
81
|
+
}
|
|
82
|
+
catch (error) {
|
|
83
|
+
if (this.config.isFailure(error)) {
|
|
84
|
+
this.onFailure(error);
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
this.onSuccess();
|
|
88
|
+
}
|
|
89
|
+
throw error;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Record a successful call
|
|
94
|
+
*/
|
|
95
|
+
onSuccess() {
|
|
96
|
+
this.metrics.successfulRequests++;
|
|
97
|
+
this.metrics.lastSuccessTime = new Date();
|
|
98
|
+
switch (this.state) {
|
|
99
|
+
case 'HALF_OPEN':
|
|
100
|
+
this.successCount++;
|
|
101
|
+
if (this.successCount >= this.config.successThreshold) {
|
|
102
|
+
this.transitionTo('CLOSED');
|
|
103
|
+
}
|
|
104
|
+
break;
|
|
105
|
+
case 'CLOSED':
|
|
106
|
+
// Reset failure count on success in closed state
|
|
107
|
+
this.failures = [];
|
|
108
|
+
break;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Record a failed call
|
|
113
|
+
*/
|
|
114
|
+
onFailure(error) {
|
|
115
|
+
this.metrics.failedRequests++;
|
|
116
|
+
this.metrics.lastFailureTime = new Date();
|
|
117
|
+
this.failures.push({
|
|
118
|
+
timestamp: Date.now(),
|
|
119
|
+
error,
|
|
120
|
+
});
|
|
121
|
+
this.cleanupOldFailures();
|
|
122
|
+
switch (this.state) {
|
|
123
|
+
case 'CLOSED':
|
|
124
|
+
if (this.failures.length >= this.config.failureThreshold) {
|
|
125
|
+
this.transitionTo('OPEN');
|
|
126
|
+
}
|
|
127
|
+
break;
|
|
128
|
+
case 'HALF_OPEN':
|
|
129
|
+
this.transitionTo('OPEN');
|
|
130
|
+
break;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Transition to a new state
|
|
135
|
+
*/
|
|
136
|
+
transitionTo(newState) {
|
|
137
|
+
if (this.state === newState)
|
|
138
|
+
return;
|
|
139
|
+
console.log(`[CircuitBreaker:${this.config.name}] ${this.state} → ${newState}`);
|
|
140
|
+
this.state = newState;
|
|
141
|
+
this.lastStateChange = new Date();
|
|
142
|
+
this.metrics.stateChanges.push({ state: newState, timestamp: this.lastStateChange });
|
|
143
|
+
if (newState === 'CLOSED') {
|
|
144
|
+
this.failures = [];
|
|
145
|
+
this.successCount = 0;
|
|
146
|
+
}
|
|
147
|
+
else if (newState === 'HALF_OPEN') {
|
|
148
|
+
this.successCount = 0;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Remove failures outside the sliding window
|
|
153
|
+
*/
|
|
154
|
+
cleanupOldFailures() {
|
|
155
|
+
const cutoff = Date.now() - this.config.windowSize;
|
|
156
|
+
this.failures = this.failures.filter(f => f.timestamp > cutoff);
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Force circuit to open
|
|
160
|
+
*/
|
|
161
|
+
forceOpen() {
|
|
162
|
+
this.transitionTo('OPEN');
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Force circuit to close
|
|
166
|
+
*/
|
|
167
|
+
forceClose() {
|
|
168
|
+
this.transitionTo('CLOSED');
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Reset circuit to initial state
|
|
172
|
+
*/
|
|
173
|
+
reset() {
|
|
174
|
+
this.state = 'CLOSED';
|
|
175
|
+
this.failures = [];
|
|
176
|
+
this.successCount = 0;
|
|
177
|
+
this.lastStateChange = new Date();
|
|
178
|
+
this.metrics = {
|
|
179
|
+
totalRequests: 0,
|
|
180
|
+
successfulRequests: 0,
|
|
181
|
+
failedRequests: 0,
|
|
182
|
+
rejectedRequests: 0,
|
|
183
|
+
stateChanges: [{ state: 'CLOSED', timestamp: new Date() }],
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* Circuit Breaker Error
|
|
189
|
+
*/
|
|
190
|
+
export class CircuitBreakerError extends Error {
|
|
191
|
+
circuitName;
|
|
192
|
+
circuitState;
|
|
193
|
+
constructor(message, circuitName, circuitState) {
|
|
194
|
+
super(message);
|
|
195
|
+
this.circuitName = circuitName;
|
|
196
|
+
this.circuitState = circuitState;
|
|
197
|
+
this.name = 'CircuitBreakerError';
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
// ============================================
|
|
201
|
+
// Circuit Breaker Registry
|
|
202
|
+
// ============================================
|
|
203
|
+
const circuitRegistry = new Map();
|
|
204
|
+
/**
|
|
205
|
+
* Get or create a circuit breaker
|
|
206
|
+
*/
|
|
207
|
+
export function getCircuitBreaker(name, config) {
|
|
208
|
+
if (!circuitRegistry.has(name)) {
|
|
209
|
+
circuitRegistry.set(name, new CircuitBreaker({ ...config, name }));
|
|
210
|
+
}
|
|
211
|
+
return circuitRegistry.get(name);
|
|
212
|
+
}
|
|
213
|
+
/**
|
|
214
|
+
* Create a new circuit breaker
|
|
215
|
+
*/
|
|
216
|
+
export function createCircuitBreaker(config = {}) {
|
|
217
|
+
const breaker = new CircuitBreaker(config);
|
|
218
|
+
if (config.name) {
|
|
219
|
+
circuitRegistry.set(config.name, breaker);
|
|
220
|
+
}
|
|
221
|
+
return breaker;
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* Get all circuit breaker statuses
|
|
225
|
+
*/
|
|
226
|
+
export function getCircuitBreakerStatus() {
|
|
227
|
+
const status = {};
|
|
228
|
+
for (const [name, breaker] of circuitRegistry) {
|
|
229
|
+
status[name] = {
|
|
230
|
+
state: breaker.getState(),
|
|
231
|
+
metrics: breaker.getMetrics(),
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
return status;
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
237
|
+
* Decorator for circuit breaker
|
|
238
|
+
*/
|
|
239
|
+
export function WithCircuitBreaker(nameOrConfig) {
|
|
240
|
+
return function (target, propertyKey, descriptor) {
|
|
241
|
+
const originalMethod = descriptor.value;
|
|
242
|
+
const config = typeof nameOrConfig === 'string' ? { name: nameOrConfig } : nameOrConfig;
|
|
243
|
+
descriptor.value = async function (...args) {
|
|
244
|
+
const breaker = getCircuitBreaker(config.name ?? propertyKey, config);
|
|
245
|
+
return breaker.execute(() => originalMethod.apply(this, args));
|
|
246
|
+
};
|
|
247
|
+
return descriptor;
|
|
248
|
+
};
|
|
249
|
+
}
|
|
250
|
+
export default CircuitBreaker;
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CanxJS Cluster Manager - Multi-process clustering for enterprise scaling
|
|
3
|
+
* @description Enables horizontal scaling across all CPU cores
|
|
4
|
+
*/
|
|
5
|
+
export interface ClusterConfig {
|
|
6
|
+
/** Enable cluster mode */
|
|
7
|
+
enabled?: boolean;
|
|
8
|
+
/** Number of workers (default: CPU cores) */
|
|
9
|
+
workers?: number | 'auto';
|
|
10
|
+
/** Restart workers on crash */
|
|
11
|
+
restartOnCrash?: boolean;
|
|
12
|
+
/** Max restarts before giving up */
|
|
13
|
+
maxRestarts?: number;
|
|
14
|
+
/** Restart delay in ms */
|
|
15
|
+
restartDelay?: number;
|
|
16
|
+
/** Grace period for shutdown in ms */
|
|
17
|
+
gracePeriod?: number;
|
|
18
|
+
/** Enable sticky sessions (for WebSocket) */
|
|
19
|
+
stickySessions?: boolean;
|
|
20
|
+
}
|
|
21
|
+
interface WorkerInfo {
|
|
22
|
+
id: number;
|
|
23
|
+
pid: number;
|
|
24
|
+
status: 'starting' | 'running' | 'stopping' | 'dead';
|
|
25
|
+
restarts: number;
|
|
26
|
+
startedAt: Date;
|
|
27
|
+
lastHeartbeat?: Date;
|
|
28
|
+
}
|
|
29
|
+
type MessageHandler = (message: WorkerMessage) => void;
|
|
30
|
+
interface WorkerMessage {
|
|
31
|
+
type: 'ready' | 'heartbeat' | 'shutdown' | 'metrics' | 'custom';
|
|
32
|
+
workerId?: number;
|
|
33
|
+
data?: unknown;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Cluster Manager for CanxJS
|
|
37
|
+
* Manages worker processes for horizontal scaling
|
|
38
|
+
*/
|
|
39
|
+
export declare class ClusterManager {
|
|
40
|
+
private config;
|
|
41
|
+
private workers;
|
|
42
|
+
private isShuttingDown;
|
|
43
|
+
private messageHandlers;
|
|
44
|
+
private workerProcesses;
|
|
45
|
+
private masterStartTime;
|
|
46
|
+
constructor(config?: ClusterConfig);
|
|
47
|
+
/**
|
|
48
|
+
* Check if running as primary/master process
|
|
49
|
+
*/
|
|
50
|
+
get isPrimary(): boolean;
|
|
51
|
+
/**
|
|
52
|
+
* Check if running as worker process
|
|
53
|
+
*/
|
|
54
|
+
get isWorker(): boolean;
|
|
55
|
+
/**
|
|
56
|
+
* Get current worker ID (if worker)
|
|
57
|
+
*/
|
|
58
|
+
get workerId(): number | null;
|
|
59
|
+
/**
|
|
60
|
+
* Get number of configured workers
|
|
61
|
+
*/
|
|
62
|
+
get workerCount(): number;
|
|
63
|
+
/**
|
|
64
|
+
* Start cluster with given app function
|
|
65
|
+
*/
|
|
66
|
+
start(appFn: () => Promise<void> | void): Promise<void>;
|
|
67
|
+
/**
|
|
68
|
+
* Start primary/master process
|
|
69
|
+
*/
|
|
70
|
+
private startPrimary;
|
|
71
|
+
/**
|
|
72
|
+
* Spawn a new worker process
|
|
73
|
+
*/
|
|
74
|
+
private spawnWorker;
|
|
75
|
+
/**
|
|
76
|
+
* Handle worker exit
|
|
77
|
+
*/
|
|
78
|
+
private handleWorkerExit;
|
|
79
|
+
/**
|
|
80
|
+
* Start worker process
|
|
81
|
+
*/
|
|
82
|
+
private startWorker;
|
|
83
|
+
/**
|
|
84
|
+
* Setup signal handlers for graceful shutdown
|
|
85
|
+
*/
|
|
86
|
+
private setupSignalHandlers;
|
|
87
|
+
/**
|
|
88
|
+
* Primary process main loop
|
|
89
|
+
*/
|
|
90
|
+
private runPrimaryLoop;
|
|
91
|
+
/**
|
|
92
|
+
* Get cluster status
|
|
93
|
+
*/
|
|
94
|
+
getStatus(): {
|
|
95
|
+
isPrimary: boolean;
|
|
96
|
+
uptime: number;
|
|
97
|
+
workers: WorkerInfo[];
|
|
98
|
+
totalRestarts: number;
|
|
99
|
+
};
|
|
100
|
+
/**
|
|
101
|
+
* Register message handler
|
|
102
|
+
*/
|
|
103
|
+
onMessage(handler: MessageHandler): void;
|
|
104
|
+
/**
|
|
105
|
+
* Broadcast message to all workers
|
|
106
|
+
*/
|
|
107
|
+
broadcast(message: WorkerMessage): void;
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Initialize cluster mode
|
|
111
|
+
*/
|
|
112
|
+
export declare function initCluster(config?: ClusterConfig): ClusterManager;
|
|
113
|
+
/**
|
|
114
|
+
* Get cluster manager instance
|
|
115
|
+
*/
|
|
116
|
+
export declare function cluster(): ClusterManager;
|
|
117
|
+
/**
|
|
118
|
+
* Cluster mode decorator/wrapper
|
|
119
|
+
*/
|
|
120
|
+
export declare function withCluster(config: ClusterConfig, appFn: () => Promise<void> | void): Promise<void>;
|
|
121
|
+
export default ClusterManager;
|
|
122
|
+
//# sourceMappingURL=ClusterManager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ClusterManager.d.ts","sourceRoot":"","sources":["../../../src/core/ClusterManager.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,MAAM,WAAW,aAAa;IAC5B,0BAA0B;IAC1B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,6CAA6C;IAC7C,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC1B,+BAA+B;IAC/B,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,oCAAoC;IACpC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,0BAA0B;IAC1B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,sCAAsC;IACtC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,6CAA6C;IAC7C,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED,UAAU,UAAU;IAClB,EAAE,EAAE,MAAM,CAAC;IACX,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,UAAU,GAAG,SAAS,GAAG,UAAU,GAAG,MAAM,CAAC;IACrD,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,IAAI,CAAC;IAChB,aAAa,CAAC,EAAE,IAAI,CAAC;CACtB;AAED,KAAK,cAAc,GAAG,CAAC,OAAO,EAAE,aAAa,KAAK,IAAI,CAAC;AAEvD,UAAU,aAAa;IACrB,IAAI,EAAE,OAAO,GAAG,WAAW,GAAG,UAAU,GAAG,SAAS,GAAG,QAAQ,CAAC;IAChE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED;;;GAGG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,MAAM,CAA0B;IACxC,OAAO,CAAC,OAAO,CAAsC;IACrD,OAAO,CAAC,cAAc,CAAS;IAC/B,OAAO,CAAC,eAAe,CAAwB;IAC/C,OAAO,CAAC,eAAe,CAA+B;IACtD,OAAO,CAAC,eAAe,CAAoB;gBAE/B,MAAM,GAAE,aAAkB;IActC;;OAEG;IACH,IAAI,SAAS,IAAI,OAAO,CAEvB;IAED;;OAEG;IACH,IAAI,QAAQ,IAAI,OAAO,CAEtB;IAED;;OAEG;IACH,IAAI,QAAQ,IAAI,MAAM,GAAG,IAAI,CAG5B;IAED;;OAEG;IACH,IAAI,WAAW,IAAI,MAAM,CAExB;IAED;;OAEG;IACG,KAAK,CAAC,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IAc7D;;OAEG;YACW,YAAY;IAyB1B;;OAEG;YACW,WAAW;IA0CzB;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAqBxB;;OAEG;YACW,WAAW;IAWzB;;OAEG;IACH,OAAO,CAAC,mBAAmB;IA2C3B;;OAEG;YACW,cAAc;IAiB5B;;OAEG;IACH,SAAS,IAAI;QACX,SAAS,EAAE,OAAO,CAAC;QACnB,MAAM,EAAE,MAAM,CAAC;QACf,OAAO,EAAE,UAAU,EAAE,CAAC;QACtB,aAAa,EAAE,MAAM,CAAC;KACvB;IAUD;;OAEG;IACH,SAAS,CAAC,OAAO,EAAE,cAAc,GAAG,IAAI;IAIxC;;OAEG;IACH,SAAS,CAAC,OAAO,EAAE,aAAa,GAAG,IAAI;CAQxC;AAOD;;GAEG;AACH,wBAAgB,WAAW,CAAC,MAAM,CAAC,EAAE,aAAa,GAAG,cAAc,CAKlE;AAED;;GAEG;AACH,wBAAgB,OAAO,IAAI,cAAc,CAKxC;AAED;;GAEG;AACH,wBAAsB,WAAW,CAC/B,MAAM,EAAE,aAAa,EACrB,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,GAChC,OAAO,CAAC,IAAI,CAAC,CAGf;AAED,eAAe,cAAc,CAAC"}
|