Skip to content

Implement circuit breaker for external price source calls #11

Description

@prodbycorne

Overview

When CoinGecko or CoinMarketCap are down or rate-limiting us, every price request waits for a full timeout before falling back. A circuit breaker will open after repeated failures and skip the failing source for a cool-down period, making responses faster and reducing load on recovering upstreams.

Behaviour

State Description
Closed Normal operation — requests pass through
Open Source is failing — skip immediately, return null
Half-open After cool-down, allow one test request; if it succeeds, close; if it fails, reopen

Configuration (per source)

CIRCUIT_BREAKER_FAILURE_THRESHOLD=3    # failures before opening
CIRCUIT_BREAKER_SUCCESS_THRESHOLD=1    # successes to close from half-open
CIRCUIT_BREAKER_TIMEOUT_MS=30000       # cool-down before half-open

Implementation

Create src/utils/circuitBreaker.js:

class CircuitBreaker {
  constructor(name, options) { ... }
  async call(fn) { ... }  // wraps the source fetch
  isOpen() { ... }
  recordSuccess() { ... }
  recordFailure() { ... }
}

Wrap each source in priceOracle.js with its own breaker instance.

Expose circuit state via GET /health:

{
  "circuits": {
    "coingecko": "closed",
    "coinmarketcap": "open",
    "stellar_dex": "closed"
  }
}

Acceptance Criteria

  • CircuitBreaker class implemented with closed/open/half-open states
  • Each price source has its own circuit breaker instance
  • Open circuit returns null immediately (no network call)
  • Circuit state visible in /health response
  • State transitions logged at INFO level
  • Unit tests for all three state transitions
  • Config via env vars with documented defaults

Metadata

Metadata

Assignees

No one assigned

    Labels

    GrantFox OSSIssue tracked in GrantFox OSSMaybe RewardedIssue may be eligible for a GrantFox rewardOfficial CampaignCampaign: Official CampaignfeatureNew feature or enhancementperformancePerformance improvements

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions