Hcs.Pool

hcs · API reference

HTTP client connection-pool support.

This module is primarily used by HCS clients. Applications generally tune it through client configuration rather than manipulating pools directly.

Connection/resource pool used by HCS clients.

Pool is a small generic pool keyed by host/port/TLS identity. HCS clients use it to reuse open connections while enforcing per-host and global limits. Application code normally configures pooling through Client, H1_client, or H2_client; use this module directly only when building custom client transports or diagnostics.

The pool does not create connections itself. Callers are responsible for:

  • computing a key with make_key;
  • acquiring an idle connection with acquire;
  • adding a freshly opened connection with add;
  • releasing a reused connection with release;
  • removing broken connections with remove;
  • closing idle or all connections with evict_idle / close_all. Example shape:
let key = Hcs.Pool.make_key ~host:"example.com" ~port:443 ~tls:true in
match Hcs.Pool.acquire pool key ~now with
| Some conn ->
    Fun.protect
      ~finally:(fun () -> Hcs.Pool.release pool key conn ~now:(clock ()))
      (fun () -> use conn)
| None ->
    let conn = connect () in
    if Hcs.Pool.add pool key conn ~now then use conn else close conn

The implementation is concurrency-safe via Kcas. It uses physical equality (==) to identify connections on release/remove, so pooled connection values should be stable heap objects.

type config = {
  max_connections_per_host : int;
  max_total_connections : int;
  idle_timeout : float;
  connection_timeout : float;
}

Pool limits.

idle_timeout is used by acquire and evict_idle to reject or evict stale idle entries. connection_timeout is configuration data for callers that need a matching connect timeout; this module does not open connections itself.

val default_config : config

Default pool settings: 10 connections per host, 100 total, 60s idle timeout, 30s connection timeout.

type key = {
  host : string;
  port : int;
  tls : bool;
}

Pool bucket key.

val make_key : host:string -> port:int -> tls:bool -> key

Build a pool key.

type 'conn t

Pool of connections of type 'conn.

val create : ?config:config -> unit -> 'conn t

Create an empty pool.

val count_for_key : 'conn t -> key -> int

Number of connections currently tracked for key.

val acquire : 'conn t -> key -> now:float -> 'conn option

Try to acquire an idle, non-expired connection for key. Marks the returned connection as in-use. Returns None when no reusable connection exists.

val release : 'conn t -> key -> 'conn -> now:float -> unit

Mark a connection as idle again and update its last-used time.

val add : 'conn t -> key -> 'conn -> now:float -> bool

Add a new in-use connection. Returns false if adding it would exceed the per-host or global limits; the caller should close the connection in that case.

val remove : 'conn t -> key -> 'conn -> unit

Remove a connection from the pool, usually after an I/O error or close.

val evict_idle : 'conn t -> now:float -> close:('conn -> unit) -> unit

Remove expired idle connections and call close for each one after removing it from the pool.

val close_all : 'conn t -> close:('conn -> unit) -> unit

Remove and close every tracked connection.

type stats = {
  total_connections : int;
  idle_connections : int;
  in_use_connections : int;
  hosts : int;
}

Snapshot of pool occupancy.

val stats : 'conn t -> stats

Return current pool statistics.