···6565 (Printf.sprintf "connect_retry_delay must be positive, got %.2f"
6666 connect_retry_delay);
67676868- Log.debug (fun m ->
6969- m
7070- "Creating config: max_connections=%d, max_idle=%.1fs, \
7171- max_lifetime=%.1fs"
7272- max_connections_per_endpoint max_idle_time max_connection_lifetime);
7368 {
7469 max_connections_per_endpoint;
7570 max_idle_time;
+14-64
lib/conpool.ml
···111111(** {1 DNS Resolution} *)
112112113113let resolve_endpoint (pool : ('clock, 'net) internal) endpoint =
114114- Log.debug (fun m -> m "Resolving %a..." Endpoint.pp endpoint);
114114+ Log.debug (fun m -> m "Resolving %a" Endpoint.pp endpoint);
115115 try
116116 let addrs =
117117 Eio.Net.getaddrinfo_stream pool.net (Endpoint.host endpoint)
118118 ~service:(string_of_int (Endpoint.port endpoint))
119119 in
120120- Log.debug (fun m -> m "Got address list for %a" Endpoint.pp endpoint);
121120 match addrs with
122121 | addr :: _ ->
123122 Log.debug (fun m ->
124123 m "Resolved %a to %a" Endpoint.pp endpoint Eio.Net.Sockaddr.pp addr);
125124 addr
126125 | [] ->
127127- Log.err (fun m ->
128128- m "Failed to resolve hostname: %s" (Endpoint.host endpoint));
126126+ (* Raise exception with error code - context will be added when caught *)
129127 raise (err (Dns_resolution_failed { hostname = Endpoint.host endpoint }))
130128 with Eio.Io _ as ex ->
131129 let bt = Printexc.get_raw_backtrace () in
···136134let rec create_connection_with_retry (pool : ('clock, 'net) internal) endpoint
137135 attempt last_error =
138136 let retry_count = Config.connect_retry_count pool.config in
139139- if attempt > retry_count then begin
140140- Log.err (fun m ->
141141- m "Failed to connect to %a after %d attempts" Endpoint.pp endpoint
142142- retry_count);
143143- raise (err (Connection_failed { endpoint; attempts = retry_count; last_error }))
144144- end;
137137+ if attempt > retry_count then
138138+ (* Raise exception with error code - context will be added when caught *)
139139+ raise (err (Connection_failed { endpoint; attempts = retry_count; last_error }));
145140146141 Log.debug (fun m ->
147142 m "Connecting to %a (attempt %d/%d)" Endpoint.pp endpoint attempt
···149144150145 try
151146 let addr = resolve_endpoint pool endpoint in
152152- Log.debug (fun m -> m "Resolved %a to address" Endpoint.pp endpoint);
153147154148 (* Connect with optional timeout *)
155149 let socket =
···323317 (Config.on_connection_closed pool.config)
324318325319let get_or_create_endpoint_pool (pool : ('clock, 'net) internal) endpoint =
326326- Log.debug (fun m ->
327327- m "Getting or creating endpoint pool for %a" Endpoint.pp endpoint);
328328-329320 (* First try with read lock *)
330321 match
331322 Eio.Mutex.use_ro pool.endpoints_mutex (fun () ->
332323 Hashtbl.find_opt pool.endpoints endpoint)
333324 with
334325 | Some ep_pool ->
335335- Log.debug (fun m ->
336336- m "Found existing endpoint pool for %a" Endpoint.pp endpoint);
337326 ep_pool
338327 | None ->
339339- Log.debug (fun m ->
340340- m "No existing pool, need to create for %a" Endpoint.pp endpoint);
341328 (* Need to create - use write lock *)
342329 Eio.Mutex.use_rw ~protect:true pool.endpoints_mutex (fun () ->
343330 (* Check again in case another fiber created it *)
344331 match Hashtbl.find_opt pool.endpoints endpoint with
345332 | Some ep_pool ->
346346- Log.debug (fun m ->
347347- m "Another fiber created pool for %a" Endpoint.pp endpoint);
348333 ep_pool
349334 | None ->
350335 (* Create new endpoint pool *)
···352337 let mutex = Eio.Mutex.create () in
353338354339 Log.info (fun m ->
355355- m "Creating new endpoint pool for %a (max_connections=%d)"
340340+ m "Creating endpoint pool for %a (max_connections=%d)"
356341 Endpoint.pp endpoint
357342 (Config.max_connections_per_endpoint pool.config));
358343359359- Log.debug (fun m ->
360360- m "About to create Eio.Pool for %a" Endpoint.pp endpoint);
361361-362344 let eio_pool =
363345 Eio.Pool.create
364346 (Config.max_connections_per_endpoint pool.config)
365347 ~validate:(fun conn ->
366366- Log.debug (fun m ->
367367- m "Validate called for connection to %a" Endpoint.pp
368368- endpoint);
369369- (* Called before reusing from pool *)
370348 let healthy = is_healthy pool ~check_readable:false conn in
371371-372349 if healthy then (
373373- Log.debug (fun m ->
374374- m "Reusing connection to %a from pool" Endpoint.pp
375375- endpoint);
376376-377350 (* Update stats for reuse *)
378351 Eio.Mutex.use_rw ~protect:true mutex (fun () ->
379352 stats.total_reused <- stats.total_reused + 1);
···388361 | Some check -> (
389362 try check (Connection.flow conn) with _ -> false)
390363 | None -> true)
391391- else begin
392392- Log.debug (fun m ->
393393- m
394394- "Connection to %a failed validation, creating new \
395395- one"
396396- Endpoint.pp endpoint);
397397- false
398398- end)
364364+ else
365365+ false)
399366 ~dispose:(fun conn ->
400367 (* Called when removing from pool *)
401368 Eio.Cancel.protect (fun () ->
···405372 Eio.Mutex.use_rw ~protect:true mutex (fun () ->
406373 stats.total_closed <- stats.total_closed + 1)))
407374 (fun () ->
408408- Log.debug (fun m ->
409409- m "Factory function called for %a" Endpoint.pp endpoint);
410375 try
411376 let conn = create_connection pool endpoint in
412377413413- Log.debug (fun m ->
414414- m "Connection created successfully for %a" Endpoint.pp
415415- endpoint);
416416-417378 (* Update stats *)
418379 Eio.Mutex.use_rw ~protect:true mutex (fun () ->
419380 stats.total_created <- stats.total_created + 1);
···424385 (Config.on_connection_created pool.config);
425386426387 conn
427427- with e ->
428428- Log.err (fun m ->
429429- m "Factory function failed for %a: %s" Endpoint.pp
430430- endpoint (Printexc.to_string e));
431431- (* Update error stats *)
388388+ with Eio.Io _ as ex ->
389389+ (* Eio.Io exceptions already have full context from create_connection.
390390+ Just update error stats and let the exception propagate. *)
432391 Eio.Mutex.use_rw ~protect:true mutex (fun () ->
433392 stats.errors <- stats.errors + 1);
434434- raise e)
393393+ raise ex)
435394 in
436436-437437- Log.debug (fun m ->
438438- m "Eio.Pool created successfully for %a" Endpoint.pp endpoint);
439395440396 let ep_pool = { pool = eio_pool; stats; mutex } in
441441-442397 Hashtbl.add pool.endpoints endpoint ep_pool;
443443- Log.debug (fun m ->
444444- m "Endpoint pool added to hashtable for %a" Endpoint.pp
445445- endpoint);
446398 ep_pool)
447399448400(** {1 Public API - Pool Creation} *)
···534486535487 `Stop_daemon
536488 with e ->
537537- (* Error - close connection so it won't be reused *)
538538- Log.warn (fun m ->
539539- m "Error with connection to %a: %s" Endpoint.pp endpoint
540540- (Printexc.to_string e));
489489+ (* Error during connection usage - close so it won't be reused.
490490+ The exception already has context from where it was raised. *)
541491 close_internal pool conn;
542492543493 (* Update error stats *)
-1
lib/endpoint.ml
···2121 (* Validate hostname is not empty *)
2222 if String.trim host = "" then invalid_arg "Hostname cannot be empty";
23232424- Log.debug (fun m -> m "Creating endpoint: %s:%d" host port);
2524 { host; port }
26252726let host t = t.host