WIP: Harden Connection Management to Prevent Zombie Connections and Indefinite Blocking#207
WIP: Harden Connection Management to Prevent Zombie Connections and Indefinite Blocking#207lucksus wants to merge 4 commits into
Conversation
…blocking Previously, wait_for_ready() would block indefinitely on a semaphore when waiting for peer connections. This caused threads to hang forever when connections failed, leading to cascading failures. Changes: - Add timeout parameter to MaybeReady::wait_for_ready() - Wrap semaphore acquire in tokio::time::timeout - Update Peer::wait_for_ready() signature to accept timeout parameter - Update all call sites to pass config.timeout This prevents threads from blocking indefinitely on failed connections.
Add methods to check if a peer connection is in a failed state, enabling proactive cleanup of zombie connections before reuse attempts. Changes: - Add MaybeReady::is_failed() to check MaybeReadyState::Failed - Add Peer::is_failed() wrapper method - Enables detection of stale connections in peer_map
Critical fix: endpoint event channel was hardcoded to 32 slots despite config specifying internal_event_channel_size=1024. This caused channel saturation under concurrent load, resulting in "closed" errors. Changes: - ep.rs: Use config.internal_event_channel_size (32→1024, 32x increase) - hub.rs: Increase hub command channel from 32→256 (8x increase) - framed.rs: Increase cmd and msg channels from 32→256 (8x increase) These increases prevent channel saturation during concurrent connection establishment and high message throughput.
Prevent failed connections from remaining in peer_map and being reused by subsequent sends, which would cause them to timeout repeatedly. Changes: - Add stale peer check in connect_peer() - remove failed peers before reuse - Add early cleanup in peer task() when connection fails during negotiation - Add cleanup in send() when wait_for_ready() times out - Add debug logging for peer lifecycle events This prevents the pattern where a failed connection stays in peer_map, gets reused by subsequent sends, and times out repeatedly (20s each time).
|
✔️ 715648d...0c9d81f - Conventional commits check succeeded. |
|
Important Review skippedDraft detected. Please check the settings in the CodeRabbit UI or the You can disable this status message by setting the ✨ Finishing touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
Even though this is paused in favor of iroh — flagging that conductors still pinned to tx5 (Holochain 0.6.x via kitsune2 0.3.x) hit the zombie-connection problem in production as an off-heap OOM, not just test flakiness. We root-caused our prod leak to the |
|
Correction to my earlier comment (#issuecomment-4732920114). I said we'd root-caused our prod OOM to the We deployed #194 + #199 fleet-wide, binary-verified, and the off-heap OOM persisted unchanged — so the zombie-PeerConnection path was not what was driving our leak. Reading per-VMA smaps showed the growing anon living in glibc malloc secondary arenas (the None of this diminishes the work in this PR. The |
In the process of diagnosing this flaky test holochain/holochain#4174, I've experimented with these changes in hope to avoid and/or mitigate loss of connection in some cases.
I'm posting this PR for visibility - stopping work on this for now in favor of the iroh transport implementation.
Summary
This PR tries to fix critical connection management issues that caused threads to block indefinitely on failed connections and allowed zombie connections to remain in the peer map, leading to cascading timeout failures. It also fixes a channel capacity bug that caused "closed" errors under concurrent load.
Problem
The existing implementation had several critical issues:
wait_for_ready()would block indefinitely on a semaphore when waiting for peer connections, causing threads to hang forever when connections failedpeer_mapand were reused by subsequent sends, causing repeated 20-second timeoutsChanges
1. Add Timeout Parameter to
wait_for_ready()(715648d)tokio::time::timeoutto prevent indefinite blockingMaybeReady::wait_for_ready()andPeer::wait_for_ready()config.timeout2. Add Failed Connection Detection (2a92be6)
MaybeReady::is_failed()to checkMaybeReadyState::FailedPeer::is_failed()wrapper method3. Fix Channel Capacity Bug (2b2dc39)
Critical fix: Endpoint event channel was hardcoded to 32 despite config specifying 1024
config.internal_event_channel_size(32→1024, 32x increase)4. Add Aggressive Peer Cleanup (0c9d81f)
Prevents failed connections from remaining in
peer_mapand being reused, which would cause repeated timeoutsconnect_peer()- remove failed peers before reusetask()when connection fails during negotiationsend()whenwait_for_ready()times outImpact
Testing
While this changed the signature of flaky test failures, it didn't (yet?) result in 100% stable connections.