Skip to content

feat(quic): add stream idle timeouts - #2947

Open
richard-ramos wants to merge 1 commit into
masterfrom
feat/quic-stream-idle-timeouts
Open

feat(quic): add stream idle timeouts#2947
richard-ramos wants to merge 1 commit into
masterfrom
feat/quic-stream-idle-timeouts

Conversation

@richard-ramos

Copy link
Copy Markdown
Member

Summary

  • Add configurable inbound and outbound inactivity timeouts for QUIC streams.
  • Reset an expired stream without closing its containing QUIC connection.
  • Refresh stream activity after successful QUIC writes.

Affected Areas

  • Transports — QUIC stream lifecycle and builder configuration

Impact on Library Users

QUIC streams now use the same five-minute default inactivity timeout as mplex and yamux. Applications can customize the values through withQuicTransport(inTimeout, outTimeout) or the QuicTransport constructors.

Risk Assessment

Long-lived QUIC streams with no reads or writes will now be reset after the configured timeout. Active sibling streams and the underlying QUIC connection remain open.

@gmelodie gmelodie left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cool! I just wonder why different timeouts for inbound and outbound streams, and why is there need for a timeout handler (what else would someone want to do other than reset the stream?)

@codecov-commenter

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 78.94737% with 4 lines in your changes missing coverage. Please review.
✅ Project coverage is 82.25%. Comparing base (9fd667d) to head (049ef16).
⚠️ Report is 2 commits behind head on master.

Files with missing lines Patch % Lines
libp2p/transports/quictransport.nim 69.23% 4 Missing ⚠️
Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##           master    #2947      +/-   ##
==========================================
+ Coverage   82.22%   82.25%   +0.03%     
==========================================
  Files         177      178       +1     
  Lines       32374    32476     +102     
  Branches       12       12              
==========================================
+ Hits        26618    26714      +96     
- Misses       5756     5762       +6     
Files with missing lines Coverage Δ
libp2p/builders.nim 77.43% <100.00%> (+0.21%) ⬆️
libp2p/transports/quictransport.nim 88.57% <69.23%> (+0.69%) ⬆️

... and 10 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@richard-ramos

Copy link
Copy Markdown
Member Author

why different timeouts for inbound and outbound stream

Good question. I copied the style for handling timeouts from withYamux and withMplex , but do not know the reasoning behind having separate parameters. Downstream i checked and both nimbus and delivery set it to 5m. .. i could set it as a single value but then lose consistency against other muxers, or... change all muxers so they have a single parameter, but then we end up with a breaking change :(

why is there need for a timeout handler (what else would someone want to do other than reset the stream?)

The timeout handler is called by the connection activity monitor once it detects that the stream got idle https://github.com/vacp2p/nim-libp2p/blob/master/libp2p/stream/connection.nim#L118-L122

@gmelodie

gmelodie commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

Claude's reasoning for the first question seems to make sense:

Trust asymmetry / DoS surface. Inbound streams are remote-initiated: a peer can open thousands and sit on them, consuming your stream IDs, flow control credit, and per-stream state. You want an aggressive "sent nothing useful within N seconds → reset" timeout there. Outbound streams are ones you opened with known intent — you know what you're waiting for (protocol negotiation response, DHT reply), so the timeout is really an application request timeout and often longer or governed by the caller's deadline instead.
Who's responsible for the first byte. On an outbound stream, you write first; the timeout measures peer responsiveness after your request. On an inbound stream, you're waiting for the opener to say something (e.g. multistream-select header in libp2p). A peer that opens a stream and stays silent is either buggy or hostile — no reason to be as patient as you'd be for a response to your own request that may legitimately take a while to compute.
Backpressure semantics differ. Timing out an outbound stream means failing your own operation — the caller usually wants to control that (context/deadline). Timing out an inbound stream is resource garbage collection — it's the muxer/transport's job, not the application's. Separate knobs because separate owners.

The timeout handler is called by the connection activity monitor once it detects that the stream got idle

I meant why does this need to be a configurable handler instead of a "static" proc, but I guess more flexibility is better if it's all the same?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: new

Development

Successfully merging this pull request may close these issues.

3 participants