A lightweight, interceptor-based load-balancing plugin for Axios
npm install axios-load-balancerA lightweight, zero-dependency load balancer for Axios. Distributes requests across multiple targets using interceptors with health tracking, automatic retries, and multiple balancing strategies.
- Multiple strategies: Round-robin, random, weighted-random, least-requests, EWMA latency
- Health tracking: Automatic failure detection with configurable thresholds
- Automatic retries: Retry failed requests on different targets
- Zero dependencies: Only requires Axios as a peer dependency
- Non-blocking: Fail-open design ensures requests are never blocked
- TypeScript: Full type definitions included
``bash`
npm install axios-load-balanceror
yarn add axios-load-balanceror
pnpm add axios-load-balancer
`typescript
import axios from 'axios';
import { attachLoadBalancer } from 'axios-load-balancer';
const client = axios.create();
const balancer = attachLoadBalancer(client, {
targets: [
'https://api1.example.com',
'https://api2.example.com',
'https://api3.example.com',
],
});
// Requests are automatically distributed across targets
const response = await client.get('/users');
`
`typescript
attachLoadBalancer(axiosInstance, {
// Required: at least one target
targets: [
'https://api1.example.com',
// Or with detailed config:
{ url: 'https://api2.example.com', weight: 2 },
],
// Optional: balancing strategy (default: 'round-robin')
strategy: 'round-robin',
// Optional: URL rewriting mode (default: 'baseURL')
urlMode: 'baseURL',
// Optional: enable debug logging
debug: false,
});
`
| Strategy | Description |
|----------|-------------|
| round-robin | Cycles through targets sequentially (default) |random
| | Selects a random target for each request |weighted-random
| | Random selection weighted by target weight |least-requests
| | Selects target with fewest in-flight requests |ewma-latency
| | Selects target with lowest exponentially weighted moving average latency |
Health tracking automatically detects failing targets and temporarily removes them from rotation.
`typescript`
attachLoadBalancer(client, {
targets: [...],
health: {
enabled: true, // Enable health tracking (default: true)
failureThreshold: 3, // Failures before marking unhealthy (default: 3)
successThreshold: 2, // Successes to recover (default: 2)
coolDownMs: 30000, // Wait time before probing (default: 30000)
timeoutMs: 5000, // Request timeout threshold (default: 5000)
probeIntervalMs: 10000, // Probe interval for cooling targets (default: 10000)
ewmaDecay: 0.2, // EWMA decay factor (default: 0.2)
},
});
Health State Machine:
``
healthy ──[failures >= threshold]──> unhealthy
│
[coolDownMs]
v
healthy <──[successes >= threshold]── cooling
Configure automatic retries on different targets when requests fail.
`typescript`
attachLoadBalancer(client, {
targets: [...],
retry: {
enabled: true, // Enable retries (default: false)
maxRetries: 2, // Maximum retry attempts (default: 2)
retryOn: ['network', 'timeout', '5xx'], // Error types to retry (default)
backoffMs: 1000, // Delay between retries (default: 1000)
},
});
Targets can be simple URLs or detailed configuration objects:
`typescript
attachLoadBalancer(client, {
targets: [
// Simple URL string
'https://api1.example.com',
// Detailed configuration
{
id: 'primary', // Optional: unique identifier
url: 'https://api2.example.com',
weight: 2, // Optional: for weighted-random strategy
metadata: { // Optional: custom metadata
region: 'us-east-1',
},
},
],
});
`
Inject balancer metadata into each request for logging or debugging:
`typescript
const balancer = attachLoadBalancer(client, {
targets: [...],
metadataKey: '_balancer',
});
client.interceptors.request.use((config) => {
console.log('Target:', config._balancer?.targetId);
return config;
});
`
attachLoadBalancer returns a handle for introspection and lifecycle control:
`typescript
const balancer = attachLoadBalancer(client, config);
// Get status of all targets
const targets = balancer.getTargets();
// [{ id, url, healthy, inFlight, latencyEWMA, failures, successes }, ...]
// Get current strategy
const strategy = balancer.getStrategy();
// Reset health state for a specific target
balancer.resetHealth('target-id');
// Reset health state for all targets
balancer.resetHealth();
// Remove interceptors and cleanup
balancer.detach();
`
Sets the target URL as baseURL on each request:
`typescript
attachLoadBalancer(client, {
targets: ['https://api1.example.com'],
urlMode: 'baseURL',
});
// client.get('/users') -> https://api1.example.com/users
`
Rewrites the full URL, useful when requests already have absolute URLs:
`typescript`
attachLoadBalancer(client, {
targets: ['https://api1.example.com'],
urlMode: 'absolute',
});
When all targets are unhealthy, the balancer selects from ALL targets rather than blocking requests. This ensures your application remains functional even during partial outages.
Full type definitions are included:
`typescript``
import type {
LoadBalancerConfig,
LoadBalancerHandle,
BalancingStrategy,
Target,
TargetConfig,
TargetStatus,
HealthConfig,
RetryConfig,
RequestMetadata,
} from 'axios-load-balancer';
MIT