ProxyManager
Enterprise-grade proxy pool manager with rotation strategies, automatic failure handling, cooldown recovery, URL-based filtering, and a comprehensive hook system.
Constructor
new ProxyManager(config: ProxyManagerConfig) ProxyManagerConfig
The config type is a union of ProxyManagerBaseConfig with one of three RotationConfig variants:
type ProxyManagerConfig = ProxyManagerBaseConfig & RotationConfig; Base Config Properties
| Property | Type | Default | Description |
|---|---|---|---|
proxies | (ProxyInfo \| string)[] | required | Array of proxies. Accepts ProxyInfo objects or URL strings. |
whitelist | (string \| RegExp)[] | undefined | URL patterns that should use proxy. If set, only matching URLs use proxy. |
blacklist | (string \| RegExp)[] | undefined | URL patterns that should NOT use proxy (go direct). Checked after whitelist. |
autoDisableDeadProxies | boolean | false | Automatically disable proxies after consecutive failures. |
maxFailures | number | 3 | Consecutive failures before disabling. |
cooldown | ProxyCooldownConfig | undefined | Cooldown config for disabled proxies. |
cooldownPeriod | number | undefined | Shorthand for cooldown: { enabled: true, durationMs: value }. |
failWithoutProxy | boolean | true | Throw error when no proxy available. Set false for direct connection fallback. |
retryWithNextProxy | boolean | false | Retry failed requests with the next proxy. |
maxProxyRetries | number | 3 | Max retry attempts when retryWithNextProxy is enabled. |
debug | boolean | false | Enable debug logging for hook errors. |
hooks | object | undefined | Event hooks (alternative to setting after construction). |
RotationStrategy
type RotationStrategy = 'random' | 'sequential' | 'per-proxy-limit'; | Strategy | Config | Description |
|---|---|---|
'random' | { rotation: 'random' } | Random proxy selection for each request. |
'sequential' | { rotation: 'sequential', requestsPerProxy?: number } | Cycle through proxies in order. Optional requests per proxy before rotating (default: 1). |
'per-proxy-limit' | { rotation: 'per-proxy-limit', limit: number } | Use each proxy for limit requests, then permanently remove it. |
ProxyCooldownConfig
interface ProxyCooldownConfig {
enabled: boolean;
durationMs: number;
} Example
import { ProxyManager } from 'rezo';
const manager = new ProxyManager({
rotation: 'random',
proxies: [
{ protocol: 'http', host: 'proxy1.example.com', port: 8080 },
'socks5://user:pass@proxy2.example.com:1080',
'http://proxy3.example.com:3128'
],
whitelist: ['api.example.com', /^https://secure./],
blacklist: ['localhost', '127.0.0.1'],
autoDisableDeadProxies: true,
maxFailures: 3,
cooldown: { enabled: true, durationMs: 30000 },
failWithoutProxy: true
}); URL Filtering
shouldProxy(url)
Checks if a URL should use a proxy based on whitelist/blacklist rules.
shouldProxy(url: string): boolean Example
manager.shouldProxy('https://api.example.com/data'); // true (matches whitelist)
manager.shouldProxy('http://localhost:3000/test'); // false (matches blacklist) Pool Inspection
getActive()
Returns all active (non-disabled) proxies.
getActive(): ProxyInfo[] getDisabled()
Returns all permanently disabled proxies (not in cooldown).
getDisabled(): ProxyInfo[] getCooldown()
Returns proxies currently in cooldown (will auto-re-enable).
getCooldown(): ProxyInfo[] getAll()
Returns the full internal ProxyState for every proxy in the pool.
getAll(): ProxyState[] getStatus()
Returns a complete status summary of the proxy pool.
getStatus(): ProxyManagerStatus Returns:
interface ProxyManagerStatus {
active: ProxyInfo[];
disabled: ProxyInfo[];
cooldown: ProxyInfo[];
total: number;
rotation: RotationStrategy;
totalRequests: number;
totalSuccesses: number;
totalFailures: number;
} Proxy Selection
next(url)
Selects the next proxy based on rotation strategy. Convenience alias for select(url).proxy.
next(url: string): ProxyInfo | null Returns null if no proxy is available or URL should go direct.
select(url)
Selects a proxy with a detailed reason. Core selection method that fires hooks, applies rotation, and updates state.
select(url: string): ProxySelectionResult Returns:
interface ProxySelectionResult {
proxy: ProxyInfo | null;
reason: 'selected' | 'blacklist-match' | 'whitelist-no-match' | 'no-proxies-available';
} Example
const proxy = manager.next('https://api.example.com/data');
if (proxy) {
console.log(`Using ${proxy.protocol}://${proxy.host}:${proxy.port}`);
}
// With detailed reason
const result = manager.select('https://api.example.com/data');
if (result.proxy) {
console.log('Selected proxy:', result.proxy.host);
} else {
console.log('No proxy because:', result.reason);
} Pool Management
add(proxies)
Adds one or more proxies to the pool. Accepts ProxyInfo objects or URL strings.
add(proxies: string | ProxyInfo | (string | ProxyInfo)[]): void remove(proxies)
Removes one or more proxies from the pool.
remove(proxies: ProxyInfo | ProxyInfo[]): void removeById(id)
Removes a proxy by its unique ID.
removeById(id: string): void reset()
Re-enables all proxies and resets all counters. Proxies remain in the pool.
reset(): void clear()
Removes all proxies and resets the pool entirely. The manager remains usable after clear().
clear(): void Example
// Add proxies
manager.add('http://new-proxy:8080');
manager.add([
{ protocol: 'socks5', host: '10.0.0.1', port: 1080 },
'http://10.0.0.2:3128'
]);
// Remove a proxy
const active = manager.getActive();
manager.remove(active[0]);
// Reset all (re-enable disabled, clear counters)
manager.reset();
// Clear everything
manager.clear(); Pool Statistics
size
Total number of proxies in the pool (active + disabled + cooldown).
get size: number totalRequests
Total requests routed through the manager.
get totalRequests: number totalSuccesses
Total successful requests.
get totalSuccesses: number totalFailures
Total failed requests.
get totalFailures: number Proxy State
getProxyState(proxy)
Returns the internal state for a specific proxy.
getProxyState(proxy: ProxyInfo): ProxyState | undefined ProxyState includes:
| Property | Type | Description |
|---|---|---|
proxy | ProxyInfo | The proxy info. |
requestCount | number | Total requests through this proxy. |
failureCount | number | Consecutive failures. |
successCount | number | Total successes. |
totalFailures | number | Lifetime failures. |
isActive | boolean | Whether the proxy is active. |
disabledReason | string | Reason for disabling ('dead', 'limit-reached', 'manual'). |
reenableAt | number | Timestamp when cooldown expires. |
lastSuccessAt | number | Timestamp of last success. |
lastFailureAt | number | Timestamp of last failure. |
lastError | string | Last error message. |
has(proxy)
Checks if a proxy exists in the pool (any state).
has(proxy: ProxyInfo): boolean hasAvailableProxies()
Checks if any proxies are active and ready to use.
hasAvailableProxies(): boolean Cooldown
isCoolingDown()
Returns true if any proxy is in cooldown (will auto-re-enable).
isCoolingDown(): boolean nextCooldownMs()
Returns milliseconds until the next proxy exits cooldown. Returns 0 if a proxy is already available, -1 if none are recovering.
nextCooldownMs(): number waitForProxy()
Returns a promise that resolves with the first proxy to become available. Resolves immediately if a proxy is already active. Rejects if no proxies are in cooldown.
waitForProxy(): Promise<ProxyInfo> Example
const proxy = manager.next(url);
if (!proxy) {
if (manager.isCoolingDown()) {
console.log(`Next proxy in ${manager.nextCooldownMs()}ms`);
const recovered = await manager.waitForProxy();
console.log('Recovered:', recovered.host);
} else {
console.log('Pool is permanently exhausted');
}
} Lifecycle
destroy()
Destroys the manager, clears all cooldown timers, and rejects pending waitForProxy() callers.
destroy(): void notifyNoProxiesAvailable(url, error)
Triggers the onNoProxiesAvailable hook with detailed pool state information.
notifyNoProxiesAvailable(url: string, error: Error): OnNoProxiesAvailableContext Hooks
The hooks property provides event hooks for the proxy lifecycle.
manager.hooks: ProxyHooks Available Hooks
| Hook | Signature | Description |
|---|---|---|
beforeProxySelect | (ctx) => ProxyInfo \| void | Override proxy selection. Return a ProxyInfo to use it. |
afterProxySelect | (ctx) => void | Notified after proxy selection. |
beforeProxyError | (ctx) => void | Before recording a proxy failure. |
afterProxyError | (ctx) => void | After recording a proxy failure. |
beforeProxyDisable | (ctx) => boolean \| void | Return false to prevent disabling. |
afterProxyDisable | (ctx) => void | After a proxy is disabled. |
afterProxyRotate | (ctx) => void | When selection rotates to a new proxy. |
afterProxyEnable | (ctx) => void | After a proxy is re-enabled. |
afterProxySuccess | (ctx) => void | After a successful request through a proxy. |
onNoProxiesAvailable | (ctx) => void | When no proxies are available. |
Example
manager.hooks.afterProxyDisable.push((ctx) => {
console.log(`Proxy ${ctx.proxy.host} disabled: ${ctx.reason}`);
if (ctx.hasCooldown) {
console.log(`Will re-enable at ${new Date(ctx.reenableAt)}`);
}
});
manager.hooks.onNoProxiesAvailable.push((ctx) => {
console.error(`Pool exhausted for ${ctx.url}`);
console.log(`Dead: ${ctx.disabledReasons.dead}, Cooldown: ${ctx.cooldownCount}`);
alertSystem.notify('Proxy pool exhausted', ctx);
});