axios-load-balancer
v0.1.0
Published
A lightweight, interceptor-based load-balancing plugin for Axios
Maintainers
Readme
axios-load-balancer
A lightweight, zero-dependency load balancer for Axios. Distributes requests across multiple targets using interceptors with health tracking, automatic retries, and multiple balancing strategies.
Features
- 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
Installation
npm install axios-load-balancer
# or
yarn add axios-load-balancer
# or
pnpm add axios-load-balancerQuick Start
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');Configuration
Basic Options
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,
});Strategies
| 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
Health tracking automatically detects failing targets and temporarily removes them from rotation.
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]── coolingAutomatic Retries
Configure automatic retries on different targets when requests fail.
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)
},
});Target Configuration
Targets can be simple URLs or detailed configuration objects:
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',
},
},
],
});Request Metadata
Inject balancer metadata into each request for logging or debugging:
const balancer = attachLoadBalancer(client, {
targets: [...],
metadataKey: '_balancer',
});
client.interceptors.request.use((config) => {
console.log('Target:', config._balancer?.targetId);
return config;
});Handle API
attachLoadBalancer returns a handle for introspection and lifecycle control:
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();URL Modes
baseURL mode (default)
Sets the target URL as baseURL on each request:
attachLoadBalancer(client, {
targets: ['https://api1.example.com'],
urlMode: 'baseURL',
});
// client.get('/users') -> https://api1.example.com/usersabsolute mode
Rewrites the full URL, useful when requests already have absolute URLs:
attachLoadBalancer(client, {
targets: ['https://api1.example.com'],
urlMode: 'absolute',
});Fail-Open Behavior
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.
TypeScript
Full type definitions are included:
import type {
LoadBalancerConfig,
LoadBalancerHandle,
BalancingStrategy,
Target,
TargetConfig,
TargetStatus,
HealthConfig,
RetryConfig,
RequestMetadata,
} from 'axios-load-balancer';License
MIT
