AoAH Day 12: Eio Connection pooling and event tracing / Dec 2025
After yesterday's
For example, github.io has four A records:
> host github.io
github.io has address 185.199.110.153
github.io has address 185.199.109.153
github.io has address 185.199.108.153
github.io has address 185.199.111.153
With this new connection pooling library, my application should be able to
connect to the github.io name and keep track of all the outgoing connections
on the basis of it being called github.io and load balance the number of
outgoing connections accordingly.
In the interests of exploring something new, I also decided to add in visualisation
support to figure out what the library is spending its time on.
I decided to generate self-contained visualisations,
inspired by
Approach
The core library itself is pretty straightforward, as it's reasonably similar to the ocaml-conduit mechanism of providing a name-based resolver. The interface should be a matter of creating a connection pool to keep track of state and then requesting a connection from it to a hostname:
module Endpoint: sig
type t
val make : host:string -> port:int -> t
end
type connection_ty = [Eio.Resource.close_ty | Eio.Flow.two_way_ty]
type connection = connection_ty Eio.Resource.t
val connection : sw:Eio.Switch.t -> t -> Endpoint.t -> connection
This uses Eio's resource mechanism to allow this connection to be used like any other.
Stacking IO errors
One of the coolest things about Eio's error handling is the ability to stack errors by re-raising exceptions and adding more context to it. I prompted the agent to also create connection-specific errors for Eio, but to integrate them into the Eio.Io extensible type. This allows errors from failures to look like this:
[WARNING] Connection attempt 3 to localhost:8088 failed:
Eio.Io Net Connection_failure Refused Unix_error
(Connection refused, "connect-in-progress", ""),
connecting to tcp:127.0.0.1:8088,
connecting to localhost:8088,
after 3 retry attempts
The conpool library can keep a lightweight reporting stack of what it's been doing while propagating the error, which makes a big different to the quality of the end logging.
Results
Self-contained visualisations work well
I activated Claude Marketplace's front end module and instructed it to generate me a self-contained HTML file with the results of the output of the stress test.
This...just worked. Here's a HTML
snapshot of the results
of a conpool run, with all the various configurations tests pushed together
into a visualisation. I've also seen

A negative result with event tracing
I figured I'd have a go at integrating at event tracing, but the various packaging problems around the tools defeated my quick attempt. There's meio which I really want to use, but it requires various upstream PRs merging, and I'll also need to figure out what to do if the ring buffer overflows. I'll have to come back to this later; for now the self-contained visualisations are fine.
Another Claude skill for tidying OCaml code
I found myself doing the same prompting repeatedly to tidy up generated code to make it more idiomatic, so I had Claude go back over my history to compact my instructions into a reusable skill, which I uploaded to ocaml-tidy-code. Running this over all the code is good to do after test cases have been generated, as then it's fairly easy to verify that things are working well.

Reflections
I find the Eio types to be quite complex after we stripped out objects, and so having an agent code up the idiomatic boilerplate required for registering Eio exceptions, pretty printers and resources was quite nice. It's also good to have another Claude skill to further refine my workflow for cleaning up code.
The self-contained visualisations are also extremely useful; in addition to the
standalone HTML one, I also vibed up a full event logging system using the
Runtime_events that
Tomorrow, we'll pull this all together into a