amqp-resilient 1.0.0
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/LICENSE +21 -0
- package/README.md +257 -0
- package/dist/connection/ConnectionManager.d.ts +84 -0
- package/dist/connection/ConnectionManager.d.ts.map +1 -0
- package/dist/connection/ConnectionManager.js +312 -0
- package/dist/connection/ConnectionManager.js.map +1 -0
- package/dist/connection/index.d.ts +2 -0
- package/dist/connection/index.d.ts.map +1 -0
- package/dist/connection/index.js +2 -0
- package/dist/connection/index.js.map +1 -0
- package/dist/consumer/BaseConsumer.d.ts +131 -0
- package/dist/consumer/BaseConsumer.d.ts.map +1 -0
- package/dist/consumer/BaseConsumer.js +398 -0
- package/dist/consumer/BaseConsumer.js.map +1 -0
- package/dist/consumer/index.d.ts +2 -0
- package/dist/consumer/index.d.ts.map +1 -0
- package/dist/consumer/index.js +2 -0
- package/dist/consumer/index.js.map +1 -0
- package/dist/health/HealthService.d.ts +46 -0
- package/dist/health/HealthService.d.ts.map +1 -0
- package/dist/health/HealthService.js +85 -0
- package/dist/health/HealthService.js.map +1 -0
- package/dist/health/index.d.ts +2 -0
- package/dist/health/index.d.ts.map +1 -0
- package/dist/health/index.js +2 -0
- package/dist/health/index.js.map +1 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +17 -0
- package/dist/index.js.map +1 -0
- package/dist/patterns/CircuitBreaker.d.ts +76 -0
- package/dist/patterns/CircuitBreaker.d.ts.map +1 -0
- package/dist/patterns/CircuitBreaker.js +156 -0
- package/dist/patterns/CircuitBreaker.js.map +1 -0
- package/dist/patterns/index.d.ts +2 -0
- package/dist/patterns/index.d.ts.map +1 -0
- package/dist/patterns/index.js +2 -0
- package/dist/patterns/index.js.map +1 -0
- package/dist/publisher/BasePublisher.d.ts +87 -0
- package/dist/publisher/BasePublisher.d.ts.map +1 -0
- package/dist/publisher/BasePublisher.js +275 -0
- package/dist/publisher/BasePublisher.js.map +1 -0
- package/dist/publisher/index.d.ts +2 -0
- package/dist/publisher/index.d.ts.map +1 -0
- package/dist/publisher/index.js +2 -0
- package/dist/publisher/index.js.map +1 -0
- package/dist/types.d.ts +184 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +35 -0
- package/dist/types.js.map +1 -0
- package/package.json +81 -0
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Health Service for tracking connection health
|
|
3
|
+
* Provides global status monitoring for all AMQP connections
|
|
4
|
+
*/
|
|
5
|
+
import { ConnectionStatus } from '../types.js';
|
|
6
|
+
/**
|
|
7
|
+
* HealthService - Singleton for tracking queue connection health
|
|
8
|
+
*/
|
|
9
|
+
class HealthServiceClass {
|
|
10
|
+
connectionStatuses = new Map();
|
|
11
|
+
/**
|
|
12
|
+
* Register or update a connection's status
|
|
13
|
+
*/
|
|
14
|
+
registerStatus(connectionName, status) {
|
|
15
|
+
this.connectionStatuses.set(connectionName, status);
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Get status of a specific connection
|
|
19
|
+
*/
|
|
20
|
+
getStatus(connectionName) {
|
|
21
|
+
return this.connectionStatuses.get(connectionName);
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Get all connection statuses
|
|
25
|
+
*/
|
|
26
|
+
getAllStatuses() {
|
|
27
|
+
return Object.fromEntries(this.connectionStatuses);
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Check if any connections are dead
|
|
31
|
+
*/
|
|
32
|
+
hasDeadConnections() {
|
|
33
|
+
for (const status of this.connectionStatuses.values()) {
|
|
34
|
+
if (status === ConnectionStatus.DEAD) {
|
|
35
|
+
return true;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return false;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Check if all connections are healthy
|
|
42
|
+
*/
|
|
43
|
+
isHealthy() {
|
|
44
|
+
if (this.connectionStatuses.size === 0) {
|
|
45
|
+
return true; // No connections configured
|
|
46
|
+
}
|
|
47
|
+
for (const status of this.connectionStatuses.values()) {
|
|
48
|
+
if (status === ConnectionStatus.DEAD || status === ConnectionStatus.DISCONNECTED) {
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return true;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Get overall status for health endpoint
|
|
56
|
+
*/
|
|
57
|
+
getOverallStatus() {
|
|
58
|
+
if (this.connectionStatuses.size === 0) {
|
|
59
|
+
return 'not_configured';
|
|
60
|
+
}
|
|
61
|
+
if (this.hasDeadConnections()) {
|
|
62
|
+
return 'dead';
|
|
63
|
+
}
|
|
64
|
+
for (const status of this.connectionStatuses.values()) {
|
|
65
|
+
if (status === ConnectionStatus.DISCONNECTED) {
|
|
66
|
+
return 'degraded';
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return 'healthy';
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Unregister a connection
|
|
73
|
+
*/
|
|
74
|
+
unregisterConnection(connectionName) {
|
|
75
|
+
this.connectionStatuses.delete(connectionName);
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Clear all connections (useful for testing)
|
|
79
|
+
*/
|
|
80
|
+
clear() {
|
|
81
|
+
this.connectionStatuses.clear();
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
export const HealthService = new HealthServiceClass();
|
|
85
|
+
//# sourceMappingURL=HealthService.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"HealthService.js","sourceRoot":"","sources":["../../src/health/HealthService.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAE/C;;GAEG;AACH,MAAM,kBAAkB;IACd,kBAAkB,GAAG,IAAI,GAAG,EAA4B,CAAC;IAEjE;;OAEG;IACH,cAAc,CAAC,cAAsB,EAAE,MAAwB;QAC7D,IAAI,CAAC,kBAAkB,CAAC,GAAG,CAAC,cAAc,EAAE,MAAM,CAAC,CAAC;IACtD,CAAC;IAED;;OAEG;IACH,SAAS,CAAC,cAAsB;QAC9B,OAAO,IAAI,CAAC,kBAAkB,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;IACrD,CAAC;IAED;;OAEG;IACH,cAAc;QACZ,OAAO,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC;IACrD,CAAC;IAED;;OAEG;IACH,kBAAkB;QAChB,KAAK,MAAM,MAAM,IAAI,IAAI,CAAC,kBAAkB,CAAC,MAAM,EAAE,EAAE,CAAC;YACtD,IAAI,MAAM,KAAK,gBAAgB,CAAC,IAAI,EAAE,CAAC;gBACrC,OAAO,IAAI,CAAC;YACd,CAAC;QACH,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC;IAED;;OAEG;IACH,SAAS;QACP,IAAI,IAAI,CAAC,kBAAkB,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;YACvC,OAAO,IAAI,CAAC,CAAC,4BAA4B;QAC3C,CAAC;QAED,KAAK,MAAM,MAAM,IAAI,IAAI,CAAC,kBAAkB,CAAC,MAAM,EAAE,EAAE,CAAC;YACtD,IAAI,MAAM,KAAK,gBAAgB,CAAC,IAAI,IAAI,MAAM,KAAK,gBAAgB,CAAC,YAAY,EAAE,CAAC;gBACjF,OAAO,KAAK,CAAC;YACf,CAAC;QACH,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;OAEG;IACH,gBAAgB;QACd,IAAI,IAAI,CAAC,kBAAkB,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;YACvC,OAAO,gBAAgB,CAAC;QAC1B,CAAC;QAED,IAAI,IAAI,CAAC,kBAAkB,EAAE,EAAE,CAAC;YAC9B,OAAO,MAAM,CAAC;QAChB,CAAC;QAED,KAAK,MAAM,MAAM,IAAI,IAAI,CAAC,kBAAkB,CAAC,MAAM,EAAE,EAAE,CAAC;YACtD,IAAI,MAAM,KAAK,gBAAgB,CAAC,YAAY,EAAE,CAAC;gBAC7C,OAAO,UAAU,CAAC;YACpB,CAAC;QACH,CAAC;QAED,OAAO,SAAS,CAAC;IACnB,CAAC;IAED;;OAEG;IACH,oBAAoB,CAAC,cAAsB;QACzC,IAAI,CAAC,kBAAkB,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC;IACjD,CAAC;IAED;;OAEG;IACH,KAAK;QACH,IAAI,CAAC,kBAAkB,CAAC,KAAK,EAAE,CAAC;IAClC,CAAC;CACF;AAED,MAAM,CAAC,MAAM,aAAa,GAAG,IAAI,kBAAkB,EAAE,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/health/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/health/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* amqp-resilient
|
|
3
|
+
* Production-ready AMQP client with retry, reconnection, and resilience patterns
|
|
4
|
+
*/
|
|
5
|
+
export { ConnectionManager } from './connection/ConnectionManager.js';
|
|
6
|
+
export { BaseConsumer } from './consumer/BaseConsumer.js';
|
|
7
|
+
export { BasePublisher } from './publisher/BasePublisher.js';
|
|
8
|
+
export { CircuitBreaker, CircuitBreakerOpenError } from './patterns/CircuitBreaker.js';
|
|
9
|
+
export { HealthService } from './health/HealthService.js';
|
|
10
|
+
export { type AmqpLogger, noopLogger, type ConnectionOptions, ConnectionStatus, type ConsumerOptions, type MessageContext, type PublisherOptions, type PublishOptions, type PublishResult, type CircuitBreakerOptions, CircuitState, } from './types.js';
|
|
11
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,iBAAiB,EAAE,MAAM,mCAAmC,CAAC;AAGtE,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAG1D,OAAO,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAG7D,OAAO,EAAE,cAAc,EAAE,uBAAuB,EAAE,MAAM,8BAA8B,CAAC;AAGvF,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAG1D,OAAO,EAEL,KAAK,UAAU,EACf,UAAU,EAEV,KAAK,iBAAiB,EACtB,gBAAgB,EAEhB,KAAK,eAAe,EACpB,KAAK,cAAc,EAEnB,KAAK,gBAAgB,EACrB,KAAK,cAAc,EACnB,KAAK,aAAa,EAElB,KAAK,qBAAqB,EAC1B,YAAY,GACb,MAAM,YAAY,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* amqp-resilient
|
|
3
|
+
* Production-ready AMQP client with retry, reconnection, and resilience patterns
|
|
4
|
+
*/
|
|
5
|
+
// Connection
|
|
6
|
+
export { ConnectionManager } from './connection/ConnectionManager.js';
|
|
7
|
+
// Consumer
|
|
8
|
+
export { BaseConsumer } from './consumer/BaseConsumer.js';
|
|
9
|
+
// Publisher
|
|
10
|
+
export { BasePublisher } from './publisher/BasePublisher.js';
|
|
11
|
+
// Patterns
|
|
12
|
+
export { CircuitBreaker, CircuitBreakerOpenError } from './patterns/CircuitBreaker.js';
|
|
13
|
+
// Health
|
|
14
|
+
export { HealthService } from './health/HealthService.js';
|
|
15
|
+
// Types
|
|
16
|
+
export { noopLogger, ConnectionStatus, CircuitState, } from './types.js';
|
|
17
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,aAAa;AACb,OAAO,EAAE,iBAAiB,EAAE,MAAM,mCAAmC,CAAC;AAEtE,WAAW;AACX,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAE1D,YAAY;AACZ,OAAO,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAE7D,WAAW;AACX,OAAO,EAAE,cAAc,EAAE,uBAAuB,EAAE,MAAM,8BAA8B,CAAC;AAEvF,SAAS;AACT,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAE1D,QAAQ;AACR,OAAO,EAGL,UAAU,EAGV,gBAAgB,EAUhB,YAAY,GACb,MAAM,YAAY,CAAC"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Circuit Breaker Pattern
|
|
3
|
+
* Prevents cascading failures by temporarily stopping operations when errors exceed threshold
|
|
4
|
+
*
|
|
5
|
+
* States:
|
|
6
|
+
* - CLOSED: Normal operation, all requests pass through
|
|
7
|
+
* - OPEN: Failure threshold exceeded, all requests fail immediately
|
|
8
|
+
* - HALF_OPEN: Testing if service has recovered (allows limited requests)
|
|
9
|
+
*/
|
|
10
|
+
import { CircuitState, type CircuitBreakerOptions } from '../types.js';
|
|
11
|
+
/**
|
|
12
|
+
* Error thrown when circuit breaker is open
|
|
13
|
+
*/
|
|
14
|
+
export declare class CircuitBreakerOpenError extends Error {
|
|
15
|
+
readonly remainingResetTime: number;
|
|
16
|
+
constructor(message: string, remainingResetTime: number);
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* CircuitBreaker - Implements the circuit breaker pattern
|
|
20
|
+
*/
|
|
21
|
+
export declare class CircuitBreaker {
|
|
22
|
+
private state;
|
|
23
|
+
private failures;
|
|
24
|
+
private successCount;
|
|
25
|
+
private lastFailureTime;
|
|
26
|
+
private readonly logger;
|
|
27
|
+
private readonly failureThreshold;
|
|
28
|
+
private readonly resetTimeout;
|
|
29
|
+
private readonly successThreshold;
|
|
30
|
+
private readonly failureWindow;
|
|
31
|
+
private readonly name;
|
|
32
|
+
constructor(options: CircuitBreakerOptions);
|
|
33
|
+
/**
|
|
34
|
+
* Execute a function with circuit breaker protection
|
|
35
|
+
*/
|
|
36
|
+
execute<T>(fn: () => Promise<T>): Promise<T>;
|
|
37
|
+
/**
|
|
38
|
+
* Record a success
|
|
39
|
+
*/
|
|
40
|
+
private onSuccess;
|
|
41
|
+
/**
|
|
42
|
+
* Record a failure
|
|
43
|
+
*/
|
|
44
|
+
private onFailure;
|
|
45
|
+
/**
|
|
46
|
+
* Remove failures outside the failure window
|
|
47
|
+
*/
|
|
48
|
+
private cleanupOldFailures;
|
|
49
|
+
/**
|
|
50
|
+
* Transition to a new state
|
|
51
|
+
*/
|
|
52
|
+
private transitionTo;
|
|
53
|
+
/**
|
|
54
|
+
* Get remaining time before reset attempt
|
|
55
|
+
*/
|
|
56
|
+
private getRemainingResetTime;
|
|
57
|
+
/**
|
|
58
|
+
* Get current state
|
|
59
|
+
*/
|
|
60
|
+
getState(): CircuitState;
|
|
61
|
+
/**
|
|
62
|
+
* Get circuit breaker stats
|
|
63
|
+
*/
|
|
64
|
+
getStats(): {
|
|
65
|
+
state: CircuitState;
|
|
66
|
+
failureCount: number;
|
|
67
|
+
successCount: number;
|
|
68
|
+
lastFailureTime: number;
|
|
69
|
+
remainingResetTime: number;
|
|
70
|
+
};
|
|
71
|
+
/**
|
|
72
|
+
* Manually reset the circuit breaker
|
|
73
|
+
*/
|
|
74
|
+
reset(): void;
|
|
75
|
+
}
|
|
76
|
+
//# sourceMappingURL=CircuitBreaker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CircuitBreaker.d.ts","sourceRoot":"","sources":["../../src/patterns/CircuitBreaker.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,EAAE,YAAY,EAA+B,KAAK,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAOpG;;GAEG;AACH,qBAAa,uBAAwB,SAAQ,KAAK;IAChD,QAAQ,CAAC,kBAAkB,EAAE,MAAM,CAAC;gBAExB,OAAO,EAAE,MAAM,EAAE,kBAAkB,EAAE,MAAM;CAKxD;AAED;;GAEG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,KAAK,CAAqC;IAClD,OAAO,CAAC,QAAQ,CAAuB;IACvC,OAAO,CAAC,YAAY,CAAK;IACzB,OAAO,CAAC,eAAe,CAAK;IAC5B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAa;IAEpC,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAS;IAC1C,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAS;IACtC,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAS;IAC1C,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAS;IACvC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAS;gBAElB,OAAO,EAAE,qBAAqB;IAS1C;;OAEG;IACG,OAAO,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IAuBlD;;OAEG;IACH,OAAO,CAAC,SAAS;IAYjB;;OAEG;IACH,OAAO,CAAC,SAAS;IAajB;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAK1B;;OAEG;IACH,OAAO,CAAC,YAAY;IAsBpB;;OAEG;IACH,OAAO,CAAC,qBAAqB;IAI7B;;OAEG;IACH,QAAQ,IAAI,YAAY;IAIxB;;OAEG;IACH,QAAQ,IAAI;QACV,KAAK,EAAE,YAAY,CAAC;QACpB,YAAY,EAAE,MAAM,CAAC;QACrB,YAAY,EAAE,MAAM,CAAC;QACrB,eAAe,EAAE,MAAM,CAAC;QACxB,kBAAkB,EAAE,MAAM,CAAC;KAC5B;IAUD;;OAEG;IACH,KAAK,IAAI,IAAI;CAId"}
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Circuit Breaker Pattern
|
|
3
|
+
* Prevents cascading failures by temporarily stopping operations when errors exceed threshold
|
|
4
|
+
*
|
|
5
|
+
* States:
|
|
6
|
+
* - CLOSED: Normal operation, all requests pass through
|
|
7
|
+
* - OPEN: Failure threshold exceeded, all requests fail immediately
|
|
8
|
+
* - HALF_OPEN: Testing if service has recovered (allows limited requests)
|
|
9
|
+
*/
|
|
10
|
+
import { CircuitState, noopLogger } from '../types.js';
|
|
11
|
+
/**
|
|
12
|
+
* Error thrown when circuit breaker is open
|
|
13
|
+
*/
|
|
14
|
+
export class CircuitBreakerOpenError extends Error {
|
|
15
|
+
remainingResetTime;
|
|
16
|
+
constructor(message, remainingResetTime) {
|
|
17
|
+
super(message);
|
|
18
|
+
this.name = 'CircuitBreakerOpenError';
|
|
19
|
+
this.remainingResetTime = remainingResetTime;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* CircuitBreaker - Implements the circuit breaker pattern
|
|
24
|
+
*/
|
|
25
|
+
export class CircuitBreaker {
|
|
26
|
+
state = CircuitState.CLOSED;
|
|
27
|
+
failures = [];
|
|
28
|
+
successCount = 0;
|
|
29
|
+
lastFailureTime = 0;
|
|
30
|
+
logger;
|
|
31
|
+
failureThreshold;
|
|
32
|
+
resetTimeout;
|
|
33
|
+
successThreshold;
|
|
34
|
+
failureWindow;
|
|
35
|
+
name;
|
|
36
|
+
constructor(options) {
|
|
37
|
+
this.name = options.name;
|
|
38
|
+
this.failureThreshold = options.failureThreshold ?? 5;
|
|
39
|
+
this.resetTimeout = options.resetTimeout ?? 30000;
|
|
40
|
+
this.successThreshold = options.successThreshold ?? 3;
|
|
41
|
+
this.failureWindow = options.failureWindow ?? 60000;
|
|
42
|
+
this.logger = options.logger ?? noopLogger;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Execute a function with circuit breaker protection
|
|
46
|
+
*/
|
|
47
|
+
async execute(fn) {
|
|
48
|
+
// Check if circuit should transition from OPEN to HALF_OPEN
|
|
49
|
+
if (this.state === CircuitState.OPEN) {
|
|
50
|
+
if (Date.now() - this.lastFailureTime >= this.resetTimeout) {
|
|
51
|
+
this.transitionTo(CircuitState.HALF_OPEN);
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
throw new CircuitBreakerOpenError(`Circuit breaker is open for ${this.name}`, this.getRemainingResetTime());
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
try {
|
|
58
|
+
const result = await fn();
|
|
59
|
+
this.onSuccess();
|
|
60
|
+
return result;
|
|
61
|
+
}
|
|
62
|
+
catch (error) {
|
|
63
|
+
this.onFailure(error instanceof Error ? error : new Error(String(error)));
|
|
64
|
+
throw error;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Record a success
|
|
69
|
+
*/
|
|
70
|
+
onSuccess() {
|
|
71
|
+
if (this.state === CircuitState.HALF_OPEN) {
|
|
72
|
+
this.successCount++;
|
|
73
|
+
if (this.successCount >= this.successThreshold) {
|
|
74
|
+
this.transitionTo(CircuitState.CLOSED);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
else if (this.state === CircuitState.CLOSED) {
|
|
78
|
+
// Clear old failures outside the window
|
|
79
|
+
this.cleanupOldFailures();
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Record a failure
|
|
84
|
+
*/
|
|
85
|
+
onFailure(error) {
|
|
86
|
+
this.lastFailureTime = Date.now();
|
|
87
|
+
this.failures.push({ timestamp: Date.now(), error });
|
|
88
|
+
this.cleanupOldFailures();
|
|
89
|
+
if (this.state === CircuitState.HALF_OPEN) {
|
|
90
|
+
// Any failure in half-open state reopens the circuit
|
|
91
|
+
this.transitionTo(CircuitState.OPEN);
|
|
92
|
+
}
|
|
93
|
+
else if (this.state === CircuitState.CLOSED && this.failures.length >= this.failureThreshold) {
|
|
94
|
+
this.transitionTo(CircuitState.OPEN);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Remove failures outside the failure window
|
|
99
|
+
*/
|
|
100
|
+
cleanupOldFailures() {
|
|
101
|
+
const cutoff = Date.now() - this.failureWindow;
|
|
102
|
+
this.failures = this.failures.filter((f) => f.timestamp > cutoff);
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Transition to a new state
|
|
106
|
+
*/
|
|
107
|
+
transitionTo(newState) {
|
|
108
|
+
const previousState = this.state;
|
|
109
|
+
this.state = newState;
|
|
110
|
+
if (newState === CircuitState.CLOSED) {
|
|
111
|
+
this.failures = [];
|
|
112
|
+
this.successCount = 0;
|
|
113
|
+
}
|
|
114
|
+
else if (newState === CircuitState.HALF_OPEN) {
|
|
115
|
+
this.successCount = 0;
|
|
116
|
+
}
|
|
117
|
+
this.logger.info({
|
|
118
|
+
circuitBreaker: this.name,
|
|
119
|
+
previousState,
|
|
120
|
+
newState,
|
|
121
|
+
failureCount: this.failures.length,
|
|
122
|
+
}, 'Circuit breaker state changed');
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Get remaining time before reset attempt
|
|
126
|
+
*/
|
|
127
|
+
getRemainingResetTime() {
|
|
128
|
+
return Math.max(0, this.resetTimeout - (Date.now() - this.lastFailureTime));
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Get current state
|
|
132
|
+
*/
|
|
133
|
+
getState() {
|
|
134
|
+
return this.state;
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Get circuit breaker stats
|
|
138
|
+
*/
|
|
139
|
+
getStats() {
|
|
140
|
+
return {
|
|
141
|
+
state: this.state,
|
|
142
|
+
failureCount: this.failures.length,
|
|
143
|
+
successCount: this.successCount,
|
|
144
|
+
lastFailureTime: this.lastFailureTime,
|
|
145
|
+
remainingResetTime: this.state === CircuitState.OPEN ? this.getRemainingResetTime() : 0,
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Manually reset the circuit breaker
|
|
150
|
+
*/
|
|
151
|
+
reset() {
|
|
152
|
+
this.transitionTo(CircuitState.CLOSED);
|
|
153
|
+
this.logger.info({ circuitBreaker: this.name }, 'Circuit breaker manually reset');
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
//# sourceMappingURL=CircuitBreaker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CircuitBreaker.js","sourceRoot":"","sources":["../../src/patterns/CircuitBreaker.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/patterns/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,uBAAuB,EAAE,MAAM,qBAAqB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/patterns/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,uBAAuB,EAAE,MAAM,qBAAqB,CAAC"}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import type { ConnectionManager } from '../connection/ConnectionManager.js';
|
|
2
|
+
import type { AmqpLogger, PublisherOptions, PublishOptions, PublishResult } from '../types.js';
|
|
3
|
+
/**
|
|
4
|
+
* BasePublisher - Base class for AMQP publishers
|
|
5
|
+
* Use this class directly or extend it for specific publishers
|
|
6
|
+
*/
|
|
7
|
+
export declare class BasePublisher {
|
|
8
|
+
protected readonly connection: ConnectionManager;
|
|
9
|
+
private channel;
|
|
10
|
+
private isInitialized;
|
|
11
|
+
private circuitBreaker;
|
|
12
|
+
protected readonly logger: AmqpLogger;
|
|
13
|
+
private readonly exchange;
|
|
14
|
+
private readonly exchangeType;
|
|
15
|
+
private readonly confirm;
|
|
16
|
+
private readonly maxRetries;
|
|
17
|
+
private readonly initialRetryDelay;
|
|
18
|
+
private readonly maxRetryDelay;
|
|
19
|
+
private readonly useCircuitBreaker;
|
|
20
|
+
constructor(connection: ConnectionManager, options: PublisherOptions);
|
|
21
|
+
/**
|
|
22
|
+
* Initialize the publisher - setup exchange
|
|
23
|
+
*/
|
|
24
|
+
initialize(): Promise<void>;
|
|
25
|
+
/**
|
|
26
|
+
* Execute single publish attempt
|
|
27
|
+
*/
|
|
28
|
+
private executePublishAttempt;
|
|
29
|
+
/**
|
|
30
|
+
* Handle publish retry logic
|
|
31
|
+
*/
|
|
32
|
+
private handlePublishRetry;
|
|
33
|
+
/**
|
|
34
|
+
* Log publish failure after all retries exhausted
|
|
35
|
+
*/
|
|
36
|
+
private logPublishFailure;
|
|
37
|
+
/**
|
|
38
|
+
* Handle circuit breaker error during publish
|
|
39
|
+
*/
|
|
40
|
+
private handleCircuitBreakerError;
|
|
41
|
+
/**
|
|
42
|
+
* Publish a message to the exchange
|
|
43
|
+
*/
|
|
44
|
+
publish(routingKey: string, message: object, options?: PublishOptions): Promise<PublishResult>;
|
|
45
|
+
/**
|
|
46
|
+
* Publish a message and throw on failure (for critical messages)
|
|
47
|
+
*/
|
|
48
|
+
publishOrThrow(routingKey: string, message: object, options?: PublishOptions): Promise<PublishResult>;
|
|
49
|
+
/**
|
|
50
|
+
* Build publish options
|
|
51
|
+
*/
|
|
52
|
+
private buildPublishOptions;
|
|
53
|
+
/**
|
|
54
|
+
* Publish with confirm channel (guaranteed delivery)
|
|
55
|
+
*/
|
|
56
|
+
private publishWithConfirm;
|
|
57
|
+
/**
|
|
58
|
+
* Publish without confirmation (fire and forget)
|
|
59
|
+
*/
|
|
60
|
+
private publishWithoutConfirm;
|
|
61
|
+
/**
|
|
62
|
+
* Internal publish implementation
|
|
63
|
+
*/
|
|
64
|
+
private doPublish;
|
|
65
|
+
/**
|
|
66
|
+
* Calculate retry delay with exponential backoff
|
|
67
|
+
*/
|
|
68
|
+
private calculateRetryDelay;
|
|
69
|
+
/**
|
|
70
|
+
* Sleep for specified milliseconds
|
|
71
|
+
*/
|
|
72
|
+
private sleep;
|
|
73
|
+
/**
|
|
74
|
+
* Get publisher stats
|
|
75
|
+
*/
|
|
76
|
+
getStats(): {
|
|
77
|
+
exchange: string;
|
|
78
|
+
isInitialized: boolean;
|
|
79
|
+
confirm: boolean;
|
|
80
|
+
circuitBreakerState?: string;
|
|
81
|
+
};
|
|
82
|
+
/**
|
|
83
|
+
* Reset circuit breaker (useful for testing or manual recovery)
|
|
84
|
+
*/
|
|
85
|
+
resetCircuitBreaker(): void;
|
|
86
|
+
}
|
|
87
|
+
//# sourceMappingURL=BasePublisher.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BasePublisher.d.ts","sourceRoot":"","sources":["../../src/publisher/BasePublisher.ts"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,oCAAoC,CAAC;AAE5E,OAAO,KAAK,EAAE,UAAU,EAAE,gBAAgB,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAU/F;;;GAGG;AACH,qBAAa,aAAa;IAetB,SAAS,CAAC,QAAQ,CAAC,UAAU,EAAE,iBAAiB;IAdlD,OAAO,CAAC,OAAO,CAAyC;IACxD,OAAO,CAAC,aAAa,CAAS;IAC9B,OAAO,CAAC,cAAc,CAA+B;IACrD,SAAS,CAAC,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAC;IAEtC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAA4C;IACzE,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAU;IAClC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAS;IAC3C,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAS;IACvC,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAU;gBAGvB,UAAU,EAAE,iBAAiB,EAChD,OAAO,EAAE,gBAAgB;IAuB3B;;OAEG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAyBjC;;OAEG;YACW,qBAAqB;IAYnC;;OAEG;YACW,kBAAkB;IAyBhC;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAkBzB;;OAEG;IACH,OAAO,CAAC,yBAAyB;IAiBjC;;OAEG;IACG,OAAO,CACX,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,MAAM,EACf,OAAO,GAAE,cAAmB,GAC3B,OAAO,CAAC,aAAa,CAAC;IAiCzB;;OAEG;IACG,cAAc,CAClB,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,MAAM,EACf,OAAO,GAAE,cAAmB,GAC3B,OAAO,CAAC,aAAa,CAAC;IAQzB;;OAEG;IACH,OAAO,CAAC,mBAAmB;IA8B3B;;OAEG;YACW,kBAAkB;IAsBhC;;OAEG;YACW,qBAAqB;IAgBnC;;OAEG;YACW,SAAS;IAiCvB;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAU3B;;OAEG;IACH,OAAO,CAAC,KAAK;IAIb;;OAEG;IACH,QAAQ,IAAI;QACV,QAAQ,EAAE,MAAM,CAAC;QACjB,aAAa,EAAE,OAAO,CAAC;QACvB,OAAO,EAAE,OAAO,CAAC;QACjB,mBAAmB,CAAC,EAAE,MAAM,CAAC;KAC9B;IASD;;OAEG;IACH,mBAAmB,IAAI,IAAI;CAG5B"}
|