@mukulchavan/resilient-http
v1.0.0
Published
A smart wrapper around fetch/axios that adds controlled retries, backoff strategies, circuit breaker pattern, and failure metrics
Maintainers
Readme
resilient-http
A smart wrapper around fetch and axios that adds controlled retries, backoff strategies, circuit breaker pattern, and failure metrics - all with minimal code changes.
🎯 The Problem
APIs fail all the time:
- Temporary network glitches
- 502 / 503 / 504 from backend
- Cold starts
- Rate limiting
- Partial outages
What teams usually do:
try {
await axios.get('/api/data');
} catch (e) {
await axios.get('/api/data'); // naive retry
}Problems:
- ❌ No backoff → thundering herd
- ❌ Infinite retries
- ❌ No failure tracking
- ❌ Can bring down entire system
✨ What This Library Does
A smart wrapper that adds:
- ✅ Controlled retries
- ✅ Backoff strategies (fixed, linear, exponential, jitter)
- ✅ Circuit breaker pattern
- ✅ Failure metrics
All with one line of code.
🔌 What Is a Circuit Breaker?
Think of it like MCB (Miniature Circuit Breaker) in your house.
| State | Meaning | |-------|---------| | Closed | API working → requests allowed | | Open | API failing → requests blocked | | Half-Open | Try few requests to test recovery |
Why it matters:
- Prevents hitting already failing services
- Saves latency & infra cost
- Improves user experience
📦 Installation
npm install resilient-http🚀 Usage
Fetch Example
import { resilientFetch } from 'resilient-http';
const response = await resilientFetch('/api/orders', {
retries: 3,
backoff: 'exponential',
retryOn: [502, 503, 504],
circuitBreaker: {
failureThreshold: 5,
resetTimeout: 30000
}
});
const data = await response.json();Axios Example
import { createResilientAxios } from 'resilient-http';
const api = createResilientAxios({
retries: 2,
backoff: 'linear'
});
// Use it like regular axios
const response = await api.get('/products');With Metrics Hooks
import { resilientFetch } from 'resilient-http';
const response = await resilientFetch('/api/data', {
retries: 3,
backoff: 'exponential',
onRetry: ({ url, attempt, error }) => {
console.log(`Retrying ${url} (attempt ${attempt})`);
},
onOpen: (url) => {
console.log(`Circuit breaker opened for ${url}`);
},
onClose: (url) => {
console.log(`Circuit breaker closed for ${url}`);
}
});⚙️ Configuration
Retry Configuration
interface RetryConfig {
retries?: number; // Number of retries (default: 3)
backoff?: 'fixed' | 'linear' | 'exponential' | 'jitter'; // Backoff strategy (default: 'exponential')
retryOn?: number[]; // HTTP status codes to retry on (default: [502, 503, 504])
initialDelay?: number; // Initial delay in ms (default: 500)
maxDelay?: number; // Maximum delay in ms (default: 30000)
timeout?: number; // Request timeout in ms (default: 0 = no timeout)
}Circuit Breaker Configuration
interface CircuitBreakerConfig {
failureThreshold?: number; // Errors before opening circuit (default: 5)
successThreshold?: number; // Successes to close circuit in half-open (default: 2)
resetTimeout?: number; // Wait before half-open in ms (default: 30000)
}Backoff Strategies
| Type | Example Delays | |------|----------------| | Fixed | 500ms, 500ms, 500ms | | Linear | 500ms, 1000ms, 1500ms | | Exponential | 500ms, 1000ms, 2000ms, 4000ms | | Jitter | Randomized exponential (reduces thundering herd) |
🔄 Retry Logic
Retry Conditions
- Network errors (connection failures)
- HTTP status codes in
retryOnlist - Timeout errors
Backoff Calculation
The library automatically calculates delays based on the selected strategy:
- Fixed: Always uses
initialDelay - Linear:
initialDelay * attempt - Exponential:
initialDelay * 2^(attempt - 1) - Jitter: Exponential with random variation (30% jitter)
🔌 Circuit Breaker Logic
How It Works
- Track failures per endpoint
- If failures ≥
failureThreshold→ OPEN - Block calls immediately (fast fail)
- After
resetTimeout→ HALF-OPEN - Test with limited calls
- If
successThresholdsuccesses → CLOSED - If any failure → OPEN again
Example Configuration
{
failureThreshold: 5, // 5 errors before opening circuit
successThreshold: 2, // 2 successes to close circuit
resetTimeout: 30000 // wait 30s before half-open
}📊 Metrics Hooks
Track retries and circuit breaker state changes:
{
onRetry: ({ url, attempt, error, statusCode }) => {
// Called on each retry attempt
},
onOpen: (url) => {
// Called when circuit breaker opens
},
onClose: (url) => {
// Called when circuit breaker closes
}
}🏗️ Architecture
Components
- Request Wrapper - Wraps fetch/axios calls, handles retries
- Retry Engine - Determines if retry is allowed, calculates delay
- Circuit Store - Maintains per-endpoint state (memory-based)
- Metrics Hook - Callbacks for monitoring
📝 TypeScript Support
Full TypeScript support with type definitions included:
import { resilientFetch, ResilientConfig } from 'resilient-http';
const config: ResilientConfig = {
retries: 3,
backoff: 'exponential',
circuitBreaker: {
failureThreshold: 5,
resetTimeout: 30000
}
};
const response = await resilientFetch('/api/data', config);🧪 Testing
Running Tests
# Install dependencies
npm install
# Run all tests
npm test
# Run tests in watch mode
npm run test:watch
# Run tests with coverage
npm run test:coverageTest Structure
The test suite includes:
- ✅ Backoff strategy tests (fixed, linear, exponential, jitter)
- ✅ Circuit breaker state transitions
- ✅ Retry logic and conditions
- ✅ Fetch wrapper integration
- ✅ Axios wrapper integration
- ✅ Metrics hooks verification
Manual Testing
You can also test the library manually using the provided test script:
# Build the project first
npm run build
# Then run manual tests (requires ts-node)
npx ts-node test-manual.ts🤝 Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
📄 License
MIT
