TCP/TLS connection pooling for Eio
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge commit '073fd4a50a6f625b8bb3e48e8c73bd27a0ee46e4'

+62 -30
+4 -4
README.md
··· 20 20 21 21 let run env = 22 22 Switch.run (fun sw -> 23 - (* Create a connection pool *) 24 - let pool = Conpool.create 23 + (* Create a basic connection pool (no protocol state) *) 24 + let pool = Conpool.create_basic 25 25 ~sw 26 26 ~net:(Eio.Stdenv.net env) 27 27 ~clock:(Eio.Stdenv.clock env) ··· 49 49 let tls_config = Tls.Config.client ~authenticator:(Ca_certs.authenticator ()) () in 50 50 51 51 (* Create pool with TLS *) 52 - let pool = Conpool.create 52 + let pool = Conpool.create_basic 53 53 ~sw 54 54 ~net:(Eio.Stdenv.net env) 55 55 ~clock:(Eio.Stdenv.clock env) ··· 76 76 () 77 77 in 78 78 79 - let pool = Conpool.create ~sw ~net ~clock ~config () 79 + let pool = Conpool.create_basic ~sw ~net ~clock ~config () 80 80 ``` 81 81 82 82 Monitor pool statistics:
+22 -18
lib/conpool.ml
··· 248 248 let conn_cancel_ref = ref (fun (_ : exn) -> ()) in 249 249 let ready_promise, ready_resolver = Eio.Promise.create () in 250 250 251 - Eio.Fiber.fork ~sw:pool.sw (fun () -> 252 - Eio.Switch.run (fun conn_sw -> 253 - conn_sw_ref := Some conn_sw; 254 - (conn_cancel_ref := fun exn -> Eio.Switch.fail conn_sw exn); 255 - (* Signal that the switch is ready *) 256 - Eio.Promise.resolve ready_resolver (); 257 - (* Block until the switch is cancelled *) 258 - let wait_forever, _never_resolved = Eio.Promise.create () in 259 - Eio.Promise.await wait_forever)); 251 + (* Use fork_daemon so connection fibers don't prevent parent switch from completing. 252 + When the parent switch completes, all connection daemon fibers are cancelled, 253 + which triggers cleanup of their inner switches and connection resources. *) 254 + Eio.Fiber.fork_daemon ~sw:pool.sw (fun () -> 255 + (try 256 + Eio.Switch.run (fun conn_sw -> 257 + conn_sw_ref := Some conn_sw; 258 + (conn_cancel_ref := fun exn -> Eio.Switch.fail conn_sw exn); 259 + (* Signal that the switch is ready *) 260 + Eio.Promise.resolve ready_resolver (); 261 + (* Block until the switch is cancelled *) 262 + Eio.Fiber.await_cancel ()) 263 + with 264 + | Eio.Cancel.Cancelled _ -> () 265 + | exn -> 266 + Log.warn (fun m -> 267 + m "Connection fiber caught exception: %s" (Printexc.to_string exn))); 268 + `Stop_daemon); 260 269 261 270 (* Wait for the switch to be created *) 262 271 Eio.Promise.await ready_promise; ··· 584 593 (** {1 Public API} *) 585 594 586 595 let create ~sw ~(net : 'net Eio.Net.t) ~(clock : 'clock Eio.Time.clock) ?tls 587 - ?(config = Config.default) ?protocol () = 588 - let protocol = 589 - match protocol with 590 - | Some p -> p 591 - | None -> 592 - Obj.magic 593 - default_protocol (* Safe: unit is compatible with any 'state *) 594 - in 595 - 596 + ?(config = Config.default) ~protocol () = 596 597 Log.info (fun m -> 597 598 m "Creating connection pool (max_per_endpoint=%d)" 598 599 (Config.max_connections_per_endpoint config)); ··· 623 624 Hashtbl.clear pool.endpoints)); 624 625 625 626 Pool pool 627 + 628 + let create_basic ~sw ~net ~clock ?tls ?config () = 629 + create ~sw ~net ~clock ?tls ?config ~protocol:default_protocol () 626 630 627 631 let connection ~sw (Pool pool) endpoint = 628 632 Log.debug (fun m -> m "Acquiring connection to %a" Endpoint.pp endpoint);
+35 -7
lib/conpool.mli
··· 13 13 14 14 For simple exclusive-access protocols (HTTP/1.x, Redis, etc.): 15 15 {[ 16 - let pool = Conpool.create ~sw ~net ~clock ~tls () in 16 + let pool = Conpool.create_basic ~sw ~net ~clock ~tls () in 17 17 Eio.Switch.run (fun conn_sw -> 18 18 let conn = Conpool.connection ~sw:conn_sw pool endpoint in 19 19 (* Use conn.flow for I/O *) ··· 105 105 106 106 (** {2 Pool Creation} *) 107 107 108 + val default_protocol : unit Config.protocol_config 109 + (** Default protocol configuration for simple exclusive-access protocols. Use 110 + with {!create} for HTTP/1.x, Redis, and similar protocols where each 111 + connection handles one request at a time with no extra state. *) 112 + 108 113 val create : 109 114 sw:Eio.Switch.t -> 110 115 net:'net Eio.Net.t -> 111 116 clock:'clock Eio.Time.clock -> 112 117 ?tls:Tls.Config.client -> 113 118 ?config:Config.t -> 114 - ?protocol:'state Config.protocol_config -> 119 + protocol:'state Config.protocol_config -> 115 120 unit -> 116 121 'state t 117 - (** Create a connection pool. 122 + (** Create a connection pool with a protocol handler. 118 123 119 124 @param sw Switch for resource management 120 125 @param net Network interface for creating connections 121 126 @param clock Clock for timeouts 122 127 @param tls Optional TLS client configuration 123 128 @param config Pool configuration (uses {!Config.default} if not provided) 124 - @param protocol 125 - Protocol handler for state management. If not provided, creates a [unit t] 126 - pool with exclusive access mode (one user per connection). 129 + @param protocol Protocol handler for state management 127 130 128 131 Examples: 129 132 130 133 Simple pool for HTTP/1.x (exclusive access, no state): 131 134 {[ 132 - let pool = Conpool.create ~sw ~net ~clock ~tls () 135 + let pool = 136 + Conpool.create ~sw ~net ~clock ~tls ~protocol:Conpool.default_protocol 137 + () 133 138 ]} 134 139 135 140 HTTP/2 pool (shared access with H2 state): 136 141 {[ 137 142 let pool = Conpool.create ~sw ~net ~clock ~tls ~protocol:h2_handler () 143 + ]} *) 144 + 145 + val create_basic : 146 + sw:Eio.Switch.t -> 147 + net:'net Eio.Net.t -> 148 + clock:'clock Eio.Time.clock -> 149 + ?tls:Tls.Config.client -> 150 + ?config:Config.t -> 151 + unit -> 152 + unit t 153 + (** Create a basic connection pool with no protocol state. 154 + 155 + This is a convenience function equivalent to: 156 + {[ 157 + Conpool.create ~sw ~net ~clock ?tls ?config 158 + ~protocol:Conpool.default_protocol () 159 + ]} 160 + 161 + Use for simple exclusive-access protocols like HTTP/1.x and Redis. 162 + 163 + Example: 164 + {[ 165 + let pool = Conpool.create_basic ~sw ~net ~clock ~tls () 138 166 ]} *) 139 167 140 168 (** {2 Connection Acquisition} *)
+1 -1
test/stress_test.ml
··· 278 278 ~connect_retry_count:3 () 279 279 in 280 280 281 - let pool = Conpool.create ~sw ~net ~clock ~config:pool_config () in 281 + let pool = Conpool.create_basic ~sw ~net ~clock ~config:pool_config () in 282 282 283 283 (* Record start time *) 284 284 let start_time = Eio.Time.now clock in