Extends: undici.Dispatcher
A pool of Client instances connected to the same upstream target with round-robin client selection.
Unlike Pool, which always selects the first available client, RoundRobinPool cycles through clients in a round-robin fashion. This ensures even distribution of requests across all connections, which is particularly useful when the upstream target is behind a load balancer that round-robins TCP connections across multiple backend servers (e.g., Kubernetes Services).
Requests are not guaranteed to be dispatched in order of invocation.
new RoundRobinPool(url[, options])Arguments:
URL | string - It should only include the protocol, hostname, and port.RoundRobinPoolOptions (optional)RoundRobinPoolOptionsExtends: ClientOptions
(origin: URL, opts: Object) => Dispatcher - Default: (origin, opts) => new Client(origin, opts)number | null (optional) - Default: null - The number of Client instances to create. When set to null, the RoundRobinPool instance will create an unlimited amount of Client instances.number | null (optional) - Default: null - The amount of time before a Client instance is removed from the RoundRobinPool and closed. When set to null, Client instances will not be removed or closed based on age.RoundRobinPool is designed for scenarios where:
http://my-service.namespace.svc)Example: In Kubernetes, when using a Service DNS name with multiple Pod replicas, kube-proxy load balances TCP connections. RoundRobinPool ensures each connection (and thus each Pod) receives an equal share of requests.
RoundRobinPool distributes HTTP requests evenly across TCP connections. Whether this translates to even backend server distribution depends on the load balancer's behavior:
✓ Works when the load balancer:
sessionAffinity✗ Does NOT work when:
How it works:
RoundRobinPool creates N TCP connections to the load balancer endpointRoundRobinPool cycles HTTP requests across those N connectionsIf the load balancer assigns all connections to the same backend (e.g., due to session affinity), RoundRobinPool cannot overcome this. In such cases, consider using BalancedPool with direct backend addresses (e.g., individual pod IPs) instead of a load-balanced endpoint.
RoundRobinPool.closedImplements Client.closed
RoundRobinPool.destroyedImplements Client.destroyed
RoundRobinPool.statsReturns PoolStats instance for this pool.
RoundRobinPool.close([callback])Implements Dispatcher.close([callback]).
RoundRobinPool.destroy([error, callback])Implements Dispatcher.destroy([error, callback]).
RoundRobinPool.connect(options[, callback])See Dispatcher.connect(options[, callback]).
RoundRobinPool.dispatch(options, handler)Implements Dispatcher.dispatch(options, handler).
RoundRobinPool.pipeline(options, handler)See Dispatcher.pipeline(options, handler).
RoundRobinPool.request(options[, callback])See Dispatcher.request(options [, callback]).
RoundRobinPool.stream(options, factory[, callback])See Dispatcher.stream(options, factory[, callback]).
RoundRobinPool.upgrade(options[, callback])See Dispatcher.upgrade(options[, callback]).
'connect'See Dispatcher Event: 'connect'.
'disconnect'See Dispatcher Event: 'disconnect'.
'drain'See Dispatcher Event: 'drain'.
import { RoundRobinPool } from 'undici'
const pool = new RoundRobinPool('http://my-service.default.svc.cluster.local', {
connections: 10
})
// Requests will be distributed evenly across all 10 connections
for (let i = 0; i < 100; i++) {
const { body } = await pool.request({
path: '/api/data',
method: 'GET'
})
console.log(await body.json())
}
await pool.close()