Tracking issue, follow-up to the deadlock PR in #1. Not a blocker. The fix bounds the wedge to one connect_timeout per slow peer, but the underlying dispatch pattern remains: the pool main loop is the only dispatcher for all peers, so each cleared backlog still costs every other peer one stall window.
Actor::handle_msg awaits entry.tx.send(msg) into a per-connection mpsc(PER_CONNECTION_INBOX = 100). When concurrency for one slow-to-connect peer exceeds 100 (the P_pending shape from #1: a peer whose endpoint.connect doesn't fail fast), that send parks for up to one connect_timeout window. The connection actor is suspended in connect_timeout and isn't draining its inbox; the actor's eventual rx close is what unblocks the pool. While parked, no other peer's RequestRef is dispatched. Worst case across N distinct slow peers each over the cap: roughly N × connect_timeout dispatch latency for an unrelated request.
Hits realistic workloads where unreachable peers don't fail fast: iroh-docs against many providers behind unstable NAT, or a startup-burst against a stale candidate list.
Mitigations (all deferred from the deadlock PR):
try_send on conn_tx in dispatch. Adds a Backpressure error variant for callers.
- Failure caching with TTL. Sidesteps dispatch for known-unreachable peers; needs an invalidation story.
- Per-peer concurrency cap at
get_or_connect entry. Admission instead of absorption.
- Per-peer dispatch tasks. Largest restructure, cleanest end state.
Tracking issue, follow-up to the deadlock PR in #1. Not a blocker. The fix bounds the wedge to one
connect_timeoutper slow peer, but the underlying dispatch pattern remains: the pool main loop is the only dispatcher for all peers, so each cleared backlog still costs every other peer one stall window.Actor::handle_msgawaitsentry.tx.send(msg)into a per-connectionmpsc(PER_CONNECTION_INBOX = 100). When concurrency for one slow-to-connect peer exceeds 100 (theP_pendingshape from #1: a peer whoseendpoint.connectdoesn't fail fast), that send parks for up to oneconnect_timeoutwindow. The connection actor is suspended inconnect_timeoutand isn't draining its inbox; the actor's eventual rx close is what unblocks the pool. While parked, no other peer'sRequestRefis dispatched. Worst case across N distinct slow peers each over the cap: roughlyN × connect_timeoutdispatch latency for an unrelated request.Hits realistic workloads where unreachable peers don't fail fast: iroh-docs against many providers behind unstable NAT, or a startup-burst against a stale candidate list.
Mitigations (all deferred from the deadlock PR):
try_sendonconn_txin dispatch. Adds aBackpressureerror variant for callers.get_or_connectentry. Admission instead of absorption.