Skip to content

Add retry logic with exponential backoff for price source HTTP calls #23

Description

@prodbycorne

Overview

All three price sources (coingecko.js, coinmarketcap.js, stellarDex.js) perform a single HTTP request with no retry. Transient network errors silently return null prices and cause anomaly false-positives. Retry with exponential backoff will dramatically improve data availability.

Retry Policy

Attempt Delay When to retry
1 Initial call
2 500 ms On network error or 429/5xx
3 2 s
4 8 s

Non-retryable: 400, 401, 403 — fail immediately (invalid API key, bad request).

Implementation

Create src/utils/fetchWithRetry.js:

async function fetchWithRetry(url, options = {}, retries = 3, baseDelayMs = 500) {
  for (let attempt = 0; attempt <= retries; attempt++) {
    try {
      const res = await axios.get(url, { timeout: 10_000, ...options });
      return res;
    } catch (err) {
      const status = err.response?.status;
      const isRetryable = !status || status === 429 || status >= 500;
      if (!isRetryable || attempt === retries) throw err;
      const delay = baseDelayMs * Math.pow(2, attempt);
      await sleep(delay);
    }
  }
}

Replace bare axios.get calls in each source file with fetchWithRetry.

For 429 responses, honour the Retry-After header if present.

Acceptance Criteria

  • fetchWithRetry utility created
  • All three source files use it
  • 429 responses respect Retry-After header when present
  • 400/401/403 errors do NOT retry
  • Retry attempts logged at DEBUG level with attempt number
  • Unit tests: success on retry-2, permanent failure after max retries, 401 no-retry
  • PRICE_SOURCE_RETRY_COUNT env var to override default (default: 3)

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