1+ /**
2+ * Circuit Breaker implementation with configurable failure thresholds and cooldown periods
3+ */
4+ class CircuitBreaker {
5+ static #instances = new Map ( ) ; // bucketId -> instance
6+
7+ constructor ( {
8+ failureThreshold = 5 ,
9+ cooldownPeriod = 30000 ,
10+ name = 'default'
11+ } ) {
12+ this . failureThreshold = failureThreshold ;
13+ this . cooldownPeriod = cooldownPeriod ;
14+ this . name = name ;
15+
16+ // State
17+ this . failCount = 0 ;
18+ this . isOpen = false ;
19+ this . openedAt = null ;
20+ this . lastFailureTime = null ;
21+ }
22+
23+ /**
24+ * Get or create a circuit breaker instance for the given bucketId
25+ * @param {string } bucketId - The service identifier
26+ * @param {Object } config - Circuit breaker configuration
27+ * @returns {CircuitBreaker } - The circuit breaker instance
28+ */
29+ static getInstance ( bucketId , config ) {
30+ if ( ! this . #instances. has ( bucketId ) ) {
31+ this . #instances. set ( bucketId , new CircuitBreaker ( {
32+ ...config ,
33+ name : `CircuitBreaker-${ bucketId } `
34+ } ) ) ;
35+ }
36+ return this . #instances. get ( bucketId ) ;
37+ }
38+
39+ /**
40+ * Clear a circuit breaker instance for the given bucketId
41+ * @param {string } bucketId - The service identifier
42+ */
43+ static clear ( bucketId ) {
44+ this . #instances. delete ( bucketId ) ;
45+ }
46+
47+ /**
48+ * Check if the circuit breaker is open, reset if cooldown period has expired
49+ * @returns {boolean } - True if circuit is open, false if closed
50+ */
51+ isCircuitOpen ( ) {
52+ if ( ! this . isOpen ) return false ;
53+
54+ // Check if cooldown period has expired
55+ if ( Date . now ( ) - this . openedAt > this . cooldownPeriod ) {
56+ this . _reset ( ) ;
57+ return false ;
58+ }
59+
60+ return true ;
61+ }
62+
63+ /**
64+ * Record a successful operation
65+ */
66+ recordSuccess ( ) {
67+ this . _reset ( ) ;
68+ }
69+
70+ /**
71+ * Record a failed operation
72+ */
73+ recordFailure ( ) {
74+ this . failCount ++ ;
75+ this . lastFailureTime = Date . now ( ) ;
76+
77+ if ( this . failCount >= this . failureThreshold ) {
78+ this . _open ( ) ;
79+ }
80+ }
81+
82+ /**
83+ * Get current circuit breaker status
84+ * @returns {Object } - Status information
85+ */
86+ getStatus ( ) {
87+ return {
88+ isOpen : this . isCircuitOpen ( ) ,
89+ failCount : this . failCount ,
90+ failureThreshold : this . failureThreshold ,
91+ cooldownRemaining : this . isOpen ?
92+ Math . max ( 0 , this . cooldownPeriod - ( Date . now ( ) - this . openedAt ) ) : 0 ,
93+ lastFailureTime : this . lastFailureTime ,
94+ name : this . name
95+ } ;
96+ }
97+
98+ /**
99+ * Manually open the circuit breaker
100+ */
101+ forceOpen ( ) {
102+ this . _open ( ) ;
103+ }
104+
105+ /**
106+ * Manually close the circuit breaker
107+ */
108+ forceClose ( ) {
109+ this . _reset ( ) ;
110+ }
111+
112+ /**
113+ * Reset circuit breaker to closed state
114+ * @private
115+ */
116+ _reset ( ) {
117+ this . isOpen = false ;
118+ this . failCount = 0 ;
119+ this . openedAt = null ;
120+ }
121+
122+ /**
123+ * Open the circuit breaker
124+ * @private
125+ */
126+ _open ( ) {
127+ this . isOpen = true ;
128+ this . openedAt = Date . now ( ) ;
129+ }
130+ }
131+
132+ export default CircuitBreaker ;
0 commit comments