This document describes the implementation of global retry logic for API fetchers to prevent data gaps and when external APIs experience temporary glitches.
- Issue: #62 - [RELIABILITY] Implement a Global "Retry" Logic
- Branch:
feature/global-retry-logic-62
A centralized retry utility has been created that provides:
- Automatic retry logic for failed HTTP requests
- Configurable retry parameters:
- Maximum number of retries (default: 3)
- Delay between retries (default: 1000ms)
- Optional exponential backoff
- Customizable retryable status codes
- Two usage patterns:
withRetry()- Wraps individual requestscreateRetryableAxiosInstance()- Creates axios instance with built-in retry
{
maxRetries: 3,
retryDelay: 1000, // 1 second
exponentialBackoff: false,
retryableStatusCodes: [408, 429, 500, 502, 503, 504]
}The utility automatically retries requests when:
- Network errors occur (no response received)
- Server returns retryable status codes:
408- Request Timeout429- Too Many Requests500- Internal Server Error502- Bad Gateway503- Service Unavailable504- Gateway Timeout
const response = await withRetry(() => axios.get(CoinGeckoFetcher.API_URL), {
maxRetries: 3,
retryDelay: 1000,
onRetry: (attempt, error, delay) => {
console.debug(`CoinGecko API retry attempt ${attempt}/3...`);
},
});All API calls wrapped with retry logic:
- CoinGecko direct GHS price
- CoinGecko XLM/USD price
- ExchangeRate API (USD to GHS)
- Alternative XLM pricing sources
Replaced custom retry implementation with centralized utility:
- Binance Spot API
- Binance P2P API
- Central Bank of Kenya API
- Alternative rate sources
Note: KES fetcher maintains its Circuit Breaker pattern for additional reliability.
All API calls wrapped with retry logic:
- VTpass API
- CoinGecko direct NGN price
- CoinGecko XLM/USD price
- ExchangeRate API (USD to NGN)
Webhook notifications now retry on failure:
- Error notifications
- Manual review notifications
import { withRetry } from "../utils/retryUtil.js";
const response = await withRetry(
() => axios.get("https://api.example.com/data"),
{ maxRetries: 3, retryDelay: 1000 },
);const response = await withRetry(
() => axios.get("https://api.example.com/data"),
{
maxRetries: 5,
retryDelay: 2000,
exponentialBackoff: true,
shouldRetry: (error) => {
// Custom logic to determine if retry should happen
return error.response?.status === 503;
},
onRetry: (attempt, error, delay) => {
console.log(`Retry ${attempt} after ${delay}ms`);
},
},
);import { createRetryableAxiosInstance } from "../utils/retryUtil.js";
const client = createRetryableAxiosInstance(
{ timeout: 5000 },
{ maxRetries: 3, retryDelay: 1000 },
);
// All requests automatically retry
const response = await client.get("https://api.example.com/data");- Prevents Data Gaps: Temporary API glitches (1-second outages) are automatically handled
- Consistent Behavior: All fetchers use the same retry logic
- Configurable: Easy to adjust retry parameters per service
- Maintainable: Centralized implementation reduces code duplication
- Observable: Debug logging for all retry attempts
- Resilient: Handles network errors and server failures gracefully
The retry logic has been integrated into existing fetchers without breaking changes. All existing tests should continue to pass.
To test retry behavior manually:
- Temporarily disable an API endpoint
- Observe retry attempts in logs
- Verify the service recovers when API becomes available
Potential improvements for future iterations:
- Add metrics/monitoring for retry attempts
- Implement adaptive retry delays based on API response headers
- Add circuit breaker pattern to other fetchers
- Create retry statistics dashboard
For adding retry logic to new fetchers:
- Import the utility:
import { withRetry } from "../../utils/retryUtil.js";- Wrap axios calls:
const response = await withRetry(() => axios.get(url, config), {
maxRetries: 3,
retryDelay: 1000,
});- Add custom retry callback (optional):
{
onRetry: (attempt, error, delay) => {
console.debug(`Retry ${attempt}/3 after ${delay}ms`);
};
}src/utils/retryUtil.ts- Core retry utilitysrc/services/marketRate/coingeckoFetcher.ts- CoinGecko implementationsrc/services/marketRate/ghsFetcher.ts- GHS implementationsrc/services/marketRate/kesFetcher.ts- KES implementationsrc/services/marketRate/ngnFetcher.ts- NGN implementationsrc/services/webhook.ts- Webhook implementation