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
Overview
All three price sources (
coingecko.js,coinmarketcap.js,stellarDex.js) perform a single HTTP request with no retry. Transient network errors silently returnnullprices and cause anomaly false-positives. Retry with exponential backoff will dramatically improve data availability.Retry Policy
Non-retryable: 400, 401, 403 — fail immediately (invalid API key, bad request).
Implementation
Create
src/utils/fetchWithRetry.js:Replace bare
axios.getcalls in each source file withfetchWithRetry.For 429 responses, honour the
Retry-Afterheader if present.Acceptance Criteria
fetchWithRetryutility createdRetry-Afterheader when presentPRICE_SOURCE_RETRY_COUNTenv var to override default (default: 3)