Advanced

Connection Pooling

Rezo reuses TCP and TLS connections automatically. When you make multiple requests to the same host, Rezo keeps sockets alive and reuses them instead of opening a new connection every time. This eliminates repeated DNS lookups, TCP handshakes, and TLS negotiations.

How It Works

  1. On the first request to a host, Rezo opens a new connection
  2. After the response completes, the socket is kept alive in a pool
  3. Subsequent requests to the same host reuse the idle socket
  4. Idle sockets are evicted after a configurable timeout

No setup is required — connection pooling is enabled by default.

import rezo from 'rezo';

// These requests automatically reuse the same connection
await rezo.get('https://api.example.com/users');
await rezo.get('https://api.example.com/posts');
// The second request skips DNS, TCP, and TLS -- it reuses the socket from the first

Configuration

Customize pooling behavior through instance configuration:

import { Rezo } from 'rezo';

const client = new Rezo({
  keepAlive: true,           // Enable keep-alive (default: true)
  keepAliveMsecs: 1000,      // Keep-alive probe interval in ms (default: 1000)
  maxSockets: 256,           // Max sockets per host (default: 256)
  maxFreeSockets: 64,        // Max idle sockets per host (default: 64)
  socketTimeout: 30000,      // Socket timeout in ms (default: 30000)
  scheduling: 'lifo',        // Socket scheduling strategy (default: 'lifo')
});

Socket Scheduling

The default lifo (Last In, First Out) strategy reuses the most recently freed socket. This keeps a small number of sockets active and lets older ones close naturally, reducing memory usage.

Use fifo if you need to distribute load evenly across connections:

const client = new Rezo({
  scheduling: 'fifo',
});

Disabling Keep-Alive

If you need a fresh connection for every request:

const client = new Rezo({
  keepAlive: false,
});

This forces Rezo to open a new TCP+TLS connection for every request and close it after the response completes. This is rarely needed but can be useful for testing or when connecting to servers that do not handle keep-alive well.

DNS Caching

Rezo caches DNS lookups by default to avoid redundant resolution on every connection. You can configure the cache behavior:

const client = new Rezo({
  dnsCache: true,  // Enable DNS caching (default: true)
});

// Or configure cache options
const client = new Rezo({
  dnsCache: {
    ttl: 300,          // Cache entries for 5 minutes
    maxEntries: 1000,  // Maximum number of cached entries
  },
});

DNS caching is especially beneficial for high-throughput workloads where the same hosts are contacted repeatedly.

Separate Pools for Different Configurations

Requests with different connection settings automatically get separate pools. For example, requests that use a proxy, a custom CA certificate, or a specific local address are pooled separately from requests with default settings. This ensures that configuration differences never interfere with each other.

Idle Socket Eviction

Idle sockets are evicted automatically when they have not been used within the eviction window:

const client = new Rezo({
  idleEvictionMs: 60000,  // Evict sockets idle for 60s (default)
});

The eviction timer does not prevent Node.js from exiting — it is safe to use in short-lived scripts without explicit cleanup.

When to Tune Pooling

For most applications, the defaults work well. Consider tuning when:

  • High concurrency: Increase maxSockets if you make many parallel requests to the same host
  • Memory-constrained environments: Decrease maxFreeSockets to limit idle socket memory
  • Long-lived connections: Increase idleEvictionMs to keep sockets alive longer between bursts of requests
  • Short-lived scripts: The defaults already handle cleanup automatically