TCP/TLS connection pooling for Eio
at main 6.1 kB view raw
1(*--------------------------------------------------------------------------- 2 Copyright (c) 2025 Anil Madhavapeddy <anil@recoil.org>. All rights reserved. 3 SPDX-License-Identifier: ISC 4 ---------------------------------------------------------------------------*) 5 6(** Conpool - Protocol-agnostic TCP/IP connection pooling library for Eio *) 7 8(** {1 Logging} *) 9 10val src : Logs.Src.t 11(** Logs source for the main connection pool. Configure logging with: 12 {[ 13 Logs.Src.set_level Conpool.src (Some Logs.Debug); 14 Logs.set_reporter (Logs_fmt.reporter ()) 15 ]} 16 17 Each submodule also exposes its own log source for fine-grained control: 18 - {!Endpoint.src} - endpoint operations 19 - {!Config.src} - pool configuration *) 20 21(** {1 Core Types} *) 22 23module Endpoint = Endpoint 24(** Network endpoint representation *) 25 26module Config = Config 27(** Configuration for connection pools *) 28 29module Stats = Stats 30(** Statistics for connection pool endpoints *) 31 32module Cmd = Cmd 33(** Cmdliner terms for connection pool configuration *) 34 35(** {1 Errors} *) 36 37type error = 38 | Dns_resolution_failed of { hostname : string } 39 (** DNS resolution failed for the given hostname *) 40 | Connection_failed of { 41 endpoint : Endpoint.t; 42 attempts : int; 43 last_error : string; 44 } (** Failed to establish connection after all retry attempts *) 45 | Connection_timeout of { endpoint : Endpoint.t; timeout : float } 46 (** Connection attempt timed out *) 47 | Invalid_config of string (** Invalid configuration parameter *) 48 | Invalid_endpoint of string (** Invalid endpoint specification *) 49 50type Eio.Exn.err += E of error 51(** Extension of Eio's error type for connection pool errors. 52 53 Pool operations raise [Eio.Io] exceptions with context information added at 54 each layer. The innermost error is often [E error], wrapped with context 55 strings that describe the operation being performed. 56 57 Example error message: 58 {[ 59 Eio.Io Conpool Dns_resolution_failed { hostname = "invalid.example" }, 60 resolving invalid.example:443, 61 connecting to invalid.example:443, 62 after 3 retry attempts 63 ]} 64 65 Use {!pp_error} to format just the error code, or let Eio format the full 66 exception with context. *) 67 68val err : error -> exn 69(** [err e] is [Eio.Exn.create (E e)]. 70 71 This converts a connection pool error to an Eio exception, allowing it to 72 be handled uniformly with other Eio I/O errors and enabling context to be 73 added via [Eio.Exn.reraise_with_context]. *) 74 75val pp_error : error Fmt.t 76(** Pretty-printer for error values (without context). 77 78 For full error messages including context, use [Eio.Exn.pp] or simply let 79 the exception be printed naturally. *) 80 81(** {1 Connection Types} *) 82 83type connection_ty = [Eio.Resource.close_ty | Eio.Flow.two_way_ty] 84(** The type tags for a pooled connection. 85 Connections support reading, writing, shutdown, and closing. *) 86 87type connection = connection_ty Eio.Resource.t 88(** A connection resource from the pool. *) 89 90(** {1 Connection Pool} *) 91 92type t 93(** Connection pool managing multiple endpoints *) 94 95val create : 96 sw:Eio.Switch.t -> 97 net:'net Eio.Net.t -> 98 clock:'clock Eio.Time.clock -> 99 ?tls:Tls.Config.client -> 100 ?config:Config.t -> 101 unit -> 102 t 103(** Create connection pool bound to switch. All connections will be closed when 104 switch is released. 105 106 @param sw Switch for resource management 107 @param net Network interface for creating connections 108 @param clock Clock for timeouts and time-based validation 109 @param tls 110 Optional TLS client configuration applied to all connections. SNI 111 servername is automatically set to the endpoint's hostname. 112 @param config 113 Optional pool configuration (uses Config.default if not provided) *) 114 115(** {1 Connection Usage} *) 116 117val connection : sw:Eio.Switch.t -> t -> Endpoint.t -> connection 118(** [connection ~sw pool endpoint] acquires a connection from the pool. 119 120 The connection is automatically returned to the pool when [sw] finishes. 121 If the connection becomes unhealthy or an error occurs during use, it is 122 closed instead of being returned to the pool. 123 124 If an idle connection is available and healthy: 125 - Reuse from pool (validates health first) 126 127 Otherwise: 128 - Create new connection (may block if endpoint at limit) 129 130 Example: 131 {[ 132 let endpoint = Conpool.Endpoint.make ~host:"example.com" ~port:443 in 133 Eio.Switch.run (fun sw -> 134 let conn = Conpool.connection ~sw pool endpoint in 135 Eio.Flow.copy_string "GET / HTTP/1.1\r\n\r\n" conn; 136 let buf = Eio.Buf_read.of_flow conn ~max_size:4096 in 137 Eio.Buf_read.take_all buf) 138 ]} *) 139 140val with_connection : t -> Endpoint.t -> (connection -> 'a) -> 'a 141(** [with_connection pool endpoint fn] is a convenience wrapper around 142 {!val:connection}. 143 144 Equivalent to: 145 {[ 146 Eio.Switch.run (fun sw -> fn (connection ~sw pool endpoint)) 147 ]} 148 149 Example: 150 {[ 151 let endpoint = Conpool.Endpoint.make ~host:"example.com" ~port:443 in 152 Conpool.with_connection pool endpoint (fun conn -> 153 (* Use conn for HTTP request, Redis command, etc. *) 154 Eio.Flow.copy_string "GET / HTTP/1.1\r\n\r\n" conn; 155 let buf = Eio.Buf_read.of_flow conn ~max_size:4096 in 156 Eio.Buf_read.take_all buf) 157 ]} *) 158 159(** {1 Statistics & Monitoring} *) 160 161val stats : t -> Endpoint.t -> Stats.t 162(** Get statistics for specific endpoint *) 163 164val all_stats : t -> (Endpoint.t * Stats.t) list 165(** Get statistics for all endpoints in pool *) 166 167(** {1 Pool Management} *) 168 169val clear_endpoint : t -> Endpoint.t -> unit 170(** Clear all cached connections for a specific endpoint. 171 172 This removes the endpoint from the pool, discarding all idle connections. 173 Active connections will continue to work but won't be returned to the pool. 174 175 Use this when you know an endpoint's connections are no longer valid (e.g., 176 server restarted, network reconfigured, credentials changed). 177 178 The pool will be automatically cleaned up when its switch is released. *)