Description
CircuitBreaker (src/lib/circuitBreaker.ts:48) stores all state — state, consecutiveFailures, lastFailureTime, lastStateChange — as private in-process fields, with config supplied only via the constructor (createCircuitBreaker(config) at src/lib/circuitBreaker.ts:186). When the API runs as multiple replicas (the repo ships a Dockerfile and docker-compose.yml), each instance trips independently, so a failing Soroban/Horizon upstream can be hammered N times over before all breakers open. This issue introduces an optional distributed (Redis-backed) state store so the breaker opens cluster-wide.
Requirements and context
- Introduce a
CircuitBreakerStore abstraction so the existing in-memory behavior becomes the default implementation and a Redis-backed implementation can be plugged in, mirroring the store-backed pattern already used by the rate limiter (src/services/rateLimiter.ts exposes InMemoryRateLimiter and a Postgres-backed store).
- Add env-driven configuration (a
CIRCUIT_BREAKER_* redis URL/enable flag) validated through src/config/env.ts / src/config/index.ts; default to in-memory when unset so local/dev/test behavior is unchanged.
- Preserve the public
execute<T>() contract and the CircuitBreakerState enum so all current callers (e.g. settlement/Horizon paths) keep working without changes.
- Non-functional: a Redis outage must fail safe (degrade to local in-memory decisions, never block requests indefinitely); reads/writes to Redis must be bounded by a timeout consistent with the health-check timeouts in
src/services/healthCheck.ts.
Acceptance criteria
Suggested execution
1. Fork the repo and create a branch
git checkout -b feature/distributed-circuit-breaker
2. Implement changes — refactor src/lib/circuitBreaker.ts to delegate to a store; add the Redis store and config plumbing.
3. Write/extend tests — extend the existing circuit-breaker unit tests and add a store-level *.test.ts; mock Redis in-process.
4. Test and commit
npm run lint
npm run typecheck
npm test -- circuitBreaker --runInBand
npm run build
Example commit message
feat(resilience): add Redis-backed distributed circuit breaker store
Guidelines
Keep the repo's 90%+ coverage target (README.md) and the existing fail-safe resilience guarantees described in RESILIENCE.md. Add JSDoc to the new store interface and document configuration in README.md. Timeframe: 96 hours.
Description
CircuitBreaker(src/lib/circuitBreaker.ts:48) stores all state —state,consecutiveFailures,lastFailureTime,lastStateChange— as private in-process fields, with config supplied only via the constructor (createCircuitBreaker(config)atsrc/lib/circuitBreaker.ts:186). When the API runs as multiple replicas (the repo ships aDockerfileanddocker-compose.yml), each instance trips independently, so a failing Soroban/Horizon upstream can be hammered N times over before all breakers open. This issue introduces an optional distributed (Redis-backed) state store so the breaker opens cluster-wide.Requirements and context
CircuitBreakerStoreabstraction so the existing in-memory behavior becomes the default implementation and a Redis-backed implementation can be plugged in, mirroring the store-backed pattern already used by the rate limiter (src/services/rateLimiter.tsexposesInMemoryRateLimiterand a Postgres-backed store).CIRCUIT_BREAKER_*redis URL/enable flag) validated throughsrc/config/env.ts/src/config/index.ts; default to in-memory when unset so local/dev/test behavior is unchanged.execute<T>()contract and theCircuitBreakerStateenum so all current callers (e.g. settlement/Horizon paths) keep working without changes.src/services/healthCheck.ts.Acceptance criteria
CircuitBreakerStoreinterface exists with in-memory (default) and Redis implementations.circuitBreakertests still pass.src/config/env.tsand documented inREADME.md/.env.example.Suggested execution
1. Fork the repo and create a branch
2. Implement changes — refactor
src/lib/circuitBreaker.tsto delegate to a store; add the Redis store and config plumbing.3. Write/extend tests — extend the existing circuit-breaker unit tests and add a store-level
*.test.ts; mock Redis in-process.4. Test and commit
npm run lint npm run typecheck npm test -- circuitBreaker --runInBand npm run buildExample commit message
Guidelines
Keep the repo's 90%+ coverage target (
README.md) and the existing fail-safe resilience guarantees described inRESILIENCE.md. Add JSDoc to the new store interface and document configuration inREADME.md. Timeframe: 96 hours.