Skip to content

Commit 5f198fa

Browse files
feat: add circuit breaker state machine — 1.1.0
1 parent bdb6695 commit 5f198fa

1 file changed

Lines changed: 54 additions & 0 deletions

File tree

src/features/circuitBreaker.ts

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import { CircuitBreakerConfig } from '../types/index.js'
2+
3+
type CircuitState = 'CLOSED' | 'OPEN' | 'HALF_OPEN'
4+
5+
type CircuitEntry = {
6+
state: CircuitState
7+
failures: number
8+
openedAt: number
9+
}
10+
11+
const circuits = new Map<string, CircuitEntry>()
12+
13+
function getEntry(key: string): CircuitEntry {
14+
if (!circuits.has(key)) {
15+
circuits.set(key, { state: 'CLOSED', failures: 0, openedAt: 0 })
16+
}
17+
return circuits.get(key)!
18+
}
19+
20+
// Returns the current state, transitioning OPEN → HALF_OPEN if the cooldown has passed.
21+
export function checkCircuit(key: string, config: CircuitBreakerConfig): CircuitState {
22+
const entry = getEntry(key)
23+
24+
if (entry.state === 'OPEN') {
25+
if (Date.now() - entry.openedAt >= config.cooldown) {
26+
entry.state = 'HALF_OPEN'
27+
return 'HALF_OPEN'
28+
}
29+
return 'OPEN'
30+
}
31+
32+
return entry.state
33+
}
34+
35+
export function recordSuccess(key: string) {
36+
const entry = getEntry(key)
37+
entry.state = 'CLOSED'
38+
entry.failures = 0
39+
}
40+
41+
export function recordFailure(key: string, config: CircuitBreakerConfig) {
42+
const entry = getEntry(key)
43+
entry.failures += 1
44+
45+
if (entry.failures >= config.threshold) {
46+
entry.state = 'OPEN'
47+
entry.openedAt = Date.now()
48+
}
49+
}
50+
51+
export function getCircuitStats(key: string): { state: CircuitState; failures: number } {
52+
const entry = getEntry(key)
53+
return { state: entry.state, failures: entry.failures }
54+
}

0 commit comments

Comments
 (0)