Skip to content

Commit f342c6b

Browse files
authored
refactor: simplify connection management and remove circuit breaker logic (#25)
- Streamlined the connection management process in the ConnectionManager and EndpointProvider by removing the circuit breaker implementation. This change enhances code readability and maintainability while preserving existing functionality. - The reconnection logic has been simplified to directly schedule reconnections without additional checks for circuit breaker states, reducing complexity and potential points of failure. - Adjusted error handling to ensure that endpoint failures are logged appropriately without the need for circuit breaker checks, allowing for a more straightforward approach to managing connection states.
1 parent 47367c4 commit f342c6b

File tree

2 files changed

+8
-119
lines changed

2 files changed

+8
-119
lines changed

packages/api/services/network/ConnectionManager.ts

Lines changed: 3 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -164,14 +164,7 @@ export class ConnectionManager {
164164

165165
// If health check fails, mark connection as not ready and attempt reconnection
166166
connection.isReady = false;
167-
168-
// Check if this is a circuit breaker situation before scheduling reconnection
169-
try {
170-
this.scheduleReconnection(network);
171-
} catch (circuitBreakerError) {
172-
// Circuit breaker is open - log but don't crash
173-
console.log(`Circuit breaker prevents reconnection for ${network}: ${circuitBreakerError instanceof Error ? circuitBreakerError.message : circuitBreakerError}`);
174-
}
167+
this.scheduleReconnection(network);
175168
}
176169
});
177170

@@ -282,12 +275,6 @@ export class ConnectionManager {
282275
const errorMessage = error instanceof Error ? error.message : String(error);
283276
console.error(`Reconnection failed for ${network}:`, errorMessage);
284277

285-
// Check if it's a circuit breaker error
286-
if (errorMessage.includes('Circuit breaker')) {
287-
console.log(`Circuit breaker active for ${network}, will retry when breaker closes`);
288-
return; // Don't increment failures for circuit breaker
289-
}
290-
291278
// Increment failure count and schedule next attempt
292279
connectionState.consecutiveFailures++;
293280

@@ -383,8 +370,8 @@ export class ConnectionManager {
383370
connectionState.consecutiveFailures++;
384371
connectionState.lastError = err;
385372

386-
// Only mark endpoint as failed if it's not a circuit breaker error
387-
if (selectedEndpoint && !err.message.includes('Circuit breaker')) {
373+
// Mark endpoint as failed
374+
if (selectedEndpoint) {
388375
this.endpointProvider.markEndpointFailed(network, selectedEndpoint);
389376
console.log(`🚫 Marked endpoint as failed: ${selectedEndpoint}`);
390377
}

packages/api/services/network/EndpointProvider.ts

Lines changed: 5 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -11,24 +11,14 @@ interface EndpointState {
1111
lastFailureTime: Date;
1212
}
1313

14-
interface CircuitBreakerState {
15-
isOpen: boolean;
16-
lastFailureTime: Date;
17-
consecutiveFailures: number;
18-
nextRetryTime: Date;
19-
}
20-
2114
export class EndpointProvider {
2215
private static instance: EndpointProvider;
2316
private endpoints: NetworkEndpoints;
2417
private currentIndex: Record<string, number> = {};
2518
private endpointStates: Map<string, EndpointState> = new Map();
2619
private lastEndpointUsed: Record<string, string> = {};
27-
private circuitBreakers: Map<string, CircuitBreakerState> = new Map();
2820

29-
// Circuit breaker configuration
30-
private readonly CIRCUIT_BREAKER_BASE_DELAY = 30000; // 30 seconds base delay
31-
private readonly CIRCUIT_BREAKER_MAX_DELAY = 300000; // 5 minutes max delay
21+
// Endpoint retry configuration
3222
private readonly ENDPOINT_RETRY_DELAY = 60000; // 1 minute before retrying a failed endpoint
3323

3424
private constructor() {
@@ -40,14 +30,6 @@ export class EndpointProvider {
4030
this.currentIndex[network] = 0;
4131
this.lastEndpointUsed[network] = '';
4232

43-
// Initialize circuit breaker state
44-
this.circuitBreakers.set(network, {
45-
isOpen: false,
46-
lastFailureTime: new Date(0),
47-
consecutiveFailures: 0,
48-
nextRetryTime: new Date(0)
49-
});
50-
5133
// Initialize endpoint states
5234
this.endpoints[network].forEach(endpoint => {
5335
this.endpointStates.set(endpoint, {
@@ -73,13 +55,6 @@ export class EndpointProvider {
7355
throw new Error(`No endpoints configured for network: ${network}`);
7456
}
7557

76-
// Check circuit breaker
77-
const circuitBreaker = this.circuitBreakers.get(network);
78-
if (circuitBreaker?.isOpen && new Date() < circuitBreaker.nextRetryTime) {
79-
const remainingTime = Math.ceil((circuitBreaker.nextRetryTime.getTime() - Date.now()) / 1000);
80-
throw new Error(`Circuit breaker open for ${network}, retry in ${remainingTime}s`);
81-
}
82-
8358
// Get available (non-blacklisted or recently failed) endpoints
8459
const now = new Date();
8560
const availableEndpoints = networkEndpoints.filter(endpoint => {
@@ -94,31 +69,21 @@ export class EndpointProvider {
9469
return timeSinceFailure > this.ENDPOINT_RETRY_DELAY;
9570
});
9671

97-
// If all endpoints are still failing, check if we should open circuit breaker
72+
// If all endpoints are still failing, try the oldest failed endpoint
9873
if (availableEndpoints.length === 0) {
99-
this.handleAllEndpointsFailed(network);
100-
101-
// Try to find the oldest failed endpoint to retry
10274
const oldestFailure = this.findOldestFailedEndpoint(network);
10375
if (oldestFailure) {
10476
this.resetEndpointState(oldestFailure);
105-
console.log(`Circuit breaker: Retrying oldest failed endpoint: ${oldestFailure}`);
77+
console.log(`All endpoints failed, retrying oldest failed endpoint: ${oldestFailure}`);
10678
return oldestFailure;
10779
}
10880

10981
// Last resort: clear all blacklists and use first endpoint
110-
console.warn(`Circuit breaker: All endpoints exhausted for ${network}, clearing blacklists`);
82+
console.warn(`All endpoints exhausted for ${network}, clearing blacklists`);
11183
this.clearBlacklist(network);
11284
return networkEndpoints[0];
11385
}
11486

115-
// Reset circuit breaker if we have available endpoints
116-
if (circuitBreaker?.isOpen) {
117-
console.log(`Circuit breaker: Endpoints recovered for ${network}, closing circuit breaker`);
118-
circuitBreaker.isOpen = false;
119-
circuitBreaker.consecutiveFailures = 0;
120-
}
121-
12287
// Smart endpoint selection: avoid recently used endpoints if possible
12388
let selectedEndpoint: string;
12489

@@ -163,42 +128,6 @@ export class EndpointProvider {
163128
state.lastUsed = new Date();
164129
console.warn(`Blacklisted endpoint for session: ${endpoint} (failure count: ${state.failureCount})`);
165130
}
166-
167-
// Check if this triggers circuit breaker
168-
this.checkCircuitBreaker(network);
169-
}
170-
171-
private handleAllEndpointsFailed(network: string): void {
172-
const circuitBreaker = this.circuitBreakers.get(network);
173-
if (!circuitBreaker) return;
174-
175-
circuitBreaker.consecutiveFailures++;
176-
circuitBreaker.lastFailureTime = new Date();
177-
178-
// Calculate exponential backoff delay
179-
const baseDelay = this.CIRCUIT_BREAKER_BASE_DELAY;
180-
const exponentialDelay = Math.min(
181-
baseDelay * Math.pow(2, circuitBreaker.consecutiveFailures - 1),
182-
this.CIRCUIT_BREAKER_MAX_DELAY
183-
);
184-
185-
circuitBreaker.nextRetryTime = new Date(Date.now() + exponentialDelay);
186-
circuitBreaker.isOpen = true;
187-
188-
console.warn(`Circuit breaker opened for ${network}: retry in ${Math.ceil(exponentialDelay / 1000)}s (attempt ${circuitBreaker.consecutiveFailures})`);
189-
}
190-
191-
private checkCircuitBreaker(network: string): void {
192-
const networkEndpoints = this.endpoints[network] || [];
193-
const allBlacklisted = networkEndpoints.every(endpoint => {
194-
const state = this.endpointStates.get(endpoint);
195-
return state?.isBlacklisted;
196-
});
197-
198-
if (allBlacklisted) {
199-
console.warn(`All endpoints blacklisted for ${network}, considering circuit breaker`);
200-
this.handleAllEndpointsFailed(network);
201-
}
202131
}
203132

204133
private findOldestFailedEndpoint(network: string): string | null {
@@ -237,27 +166,12 @@ export class EndpointProvider {
237166
state.lastUsed = new Date(0);
238167
}
239168
});
240-
241-
// Reset circuit breaker
242-
const circuitBreaker = this.circuitBreakers.get(network);
243-
if (circuitBreaker) {
244-
circuitBreaker.isOpen = false;
245-
circuitBreaker.consecutiveFailures = 0;
246-
circuitBreaker.nextRetryTime = new Date(0);
247-
}
248169
} else {
249170
// Clear all blacklisted endpoints
250171
this.endpointStates.forEach(state => {
251172
state.isBlacklisted = false;
252173
state.lastUsed = new Date(0);
253174
});
254-
255-
// Reset all circuit breakers
256-
this.circuitBreakers.forEach(circuitBreaker => {
257-
circuitBreaker.isOpen = false;
258-
circuitBreaker.consecutiveFailures = 0;
259-
circuitBreaker.nextRetryTime = new Date(0);
260-
});
261175
}
262176
}
263177

@@ -266,11 +180,6 @@ export class EndpointProvider {
266180
available: number;
267181
blacklisted: string[];
268182
endpointDetails: Record<string, { failureCount: number; lastUsed: string; isBlacklisted: boolean }>;
269-
circuitBreaker: {
270-
isOpen: boolean;
271-
consecutiveFailures: number;
272-
nextRetryTime: string;
273-
};
274183
} {
275184
const networkEndpoints = this.endpoints[network] || [];
276185
const blacklisted = networkEndpoints.filter(endpoint => {
@@ -288,18 +197,11 @@ export class EndpointProvider {
288197
};
289198
});
290199

291-
const circuitBreaker = this.circuitBreakers.get(network);
292-
293200
return {
294201
total: networkEndpoints.length,
295202
available: networkEndpoints.length - blacklisted.length,
296203
blacklisted,
297-
endpointDetails,
298-
circuitBreaker: {
299-
isOpen: circuitBreaker?.isOpen || false,
300-
consecutiveFailures: circuitBreaker?.consecutiveFailures || 0,
301-
nextRetryTime: circuitBreaker?.nextRetryTime.toISOString() || 'never'
302-
}
204+
endpointDetails
303205
};
304206
}
305207
}

0 commit comments

Comments
 (0)