How to debug *why* a channel closed?

i’ve been trying to investigate a flaky CI test that sporadically fails because of ioOnClosedChannel. it is difficult to reproduce locally, and i’ve only been able to reproduce the failure by artificially limiting the CPU percentage available to the mock servers to a very low percentage, like 3%, to simulate a GitHub Actions runner under high contention.

but i have been unable to make much progress investigating the issue because i have no idea how to log why a channel was closed in the first place! i thought perhaps the failure(_:) case of the closeFuture result might contain useful information. but the closeFuture always reports “success”. so i do not know if there is faulty logic on my end and i am somehow checking-out bad connections on the client side, or if the server is just hanging up on its own due to low resources.

how to i detect which side a channel was closed from?

Yes, closeFuture essentially never fails. It's a simple signal of closure.

Unfortunately, NIO doesn't provide good insight on this. Our shutdown path is basically identical in both cases. The easiest way to get some confidence is to add a ChannelHandler to the front of both pipelines that prints on func close, and use that to indicate who asked for the closure. You could consider using swift-nio-extras DebugOutboundEventsHandler as well to get even more clarity, potentially combining it with its inbound equivalent.

1 Like

In general, though, I'll note that NIO rarely closes a channel on its own behalf without providing an error. Implementing errorCaught may illuminate you.