Skip to content

refactor: stop EndpointDriver once endpoint is closed and all connections are drained#426

Merged
divagant-martian merged 4 commits intomainfrom
Frando/stop-driver-on-close
Feb 13, 2026
Merged

refactor: stop EndpointDriver once endpoint is closed and all connections are drained#426
divagant-martian merged 4 commits intomainfrom
Frando/stop-driver-on-close

Conversation

@Frando
Copy link
Copy Markdown
Member

@Frando Frando commented Feb 13, 2026

Description

Currently, the quinn::EndpointDriver is only stopped once all Endpoint structs are dropped. This changes it such that if Endpoint::close has been called, and all connections are drained, then the endpoint driver stops.

I think the change is fine, upon some investigation I couldn't find anything that would change in behavior apart from that potentially it would poll less often for new Incomings. However, the notification for new Incomings in the Accept future already is only registered if the endpoint is not closed. So I don't think this actually changes anything.

This change will make our life in iroh much easier, see n0-computer/iroh#3879: We no longer have to ensure that the quinn::Endpoint is dropped to wait for the driver task to stop.

Breaking Changes

Notes & open questions

@github-actions
Copy link
Copy Markdown

github-actions bot commented Feb 13, 2026

Documentation for this PR has been generated and is available at: https://n0-computer.github.io/quinn/pr/426/docs/iroh_quinn/

Last updated: 2026-02-13T11:32:39Z

@codecov-commenter
Copy link
Copy Markdown

codecov-commenter commented Feb 13, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 77.30%. Comparing base (315f491) to head (b693e9b).

Additional details and impacted files
@@            Coverage Diff             @@
##             main     #426      +/-   ##
==========================================
- Coverage   77.35%   77.30%   -0.05%     
==========================================
  Files          81       81              
  Lines       23351    23356       +5     
==========================================
- Hits        18062    18056       -6     
- Misses       5289     5300      +11     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

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

@github-actions
Copy link
Copy Markdown

github-actions bot commented Feb 13, 2026

Performance Comparison Report

f817aa90724084118a6973293699d7b5010126f5 - artifacts

Raw Benchmarks (localhost)

Scenario iroh-quinn upstream Delta CPU (avg/max)
large-single 5340.6 Mbps 7885.1 Mbps -32.3% 95.4% / 105.0%
medium-concurrent 5355.6 Mbps 7945.1 Mbps -32.6% 93.8% / 104.0%
medium-single 4126.0 Mbps 4749.8 Mbps -13.1% 97.5% / 158.0%
small-concurrent 3866.4 Mbps 4951.2 Mbps -21.9% 99.3% / 161.0%
small-single 3558.9 Mbps 4839.4 Mbps -26.5% 95.2% / 108.0%

Netsim Benchmarks (network simulation)

Condition iroh-quinn upstream Delta
ideal 3049.1 Mbps 3656.1 Mbps -16.6%
lan 782.5 Mbps 796.4 Mbps -1.7%
lossy 69.8 Mbps 69.8 Mbps ~0%
wan 83.8 Mbps 83.8 Mbps ~0%

Summary

iroh-quinn is 25.0% slower on average

---
272f7e258c2627f9582eb5937de0b9d2a7db1e8c - artifacts

Raw Benchmarks (localhost)

Scenario iroh-quinn upstream Delta CPU (avg/max)
large-single 5599.6 Mbps 7933.6 Mbps -29.4% 95.8% / 106.0%
medium-concurrent 5415.6 Mbps 7921.6 Mbps -31.6% 95.6% / 105.0%
medium-single 3921.9 Mbps 4749.1 Mbps -17.4% 90.0% / 97.6%
small-concurrent 3859.7 Mbps 5203.4 Mbps -25.8% 95.1% / 106.0%
small-single 3461.4 Mbps 4731.8 Mbps -26.8% 98.2% / 161.0%

Summary

iroh-quinn is 27.1% slower on average

---
824f1b609253069fcb377d2befb4ce7134948566 - artifacts

Raw Benchmarks (localhost)

Scenario iroh-quinn upstream Delta CPU (avg/max)
large-single 5386.9 Mbps N/A N/A 88.1% / 95.3%
medium-concurrent 5402.9 Mbps N/A N/A 92.0% / 97.2%
medium-single 3807.8 Mbps N/A N/A 94.3% / 120.0%
small-concurrent 3816.9 Mbps N/A N/A 86.1% / 97.0%
small-single 3343.5 Mbps N/A N/A 89.7% / 97.6%

Netsim Benchmarks (network simulation)

Condition iroh-quinn upstream Delta
ideal 2963.2 Mbps N/A N/A
lan 782.5 Mbps N/A N/A
wan 83.8 Mbps N/A N/A
---
b693e9b0cc1cca4bd6b558993410d3d33eda6aaa - artifacts

Raw Benchmarks (localhost)

Scenario iroh-quinn upstream Delta CPU (avg/max)
large-single 5367.2 Mbps 7971.4 Mbps -32.7% 90.5% / 97.0%
medium-concurrent 5165.2 Mbps 7802.9 Mbps -33.8% 90.0% / 96.2%
medium-single 4044.4 Mbps 4749.0 Mbps -14.8% 94.5% / 123.0%
small-concurrent 3773.1 Mbps 5274.9 Mbps -28.5% 87.8% / 97.4%
small-single 3438.6 Mbps 4824.3 Mbps -28.7% 94.0% / 126.0%

Netsim Benchmarks (network simulation)

Condition iroh-quinn upstream Delta
ideal 2947.0 Mbps N/A N/A
lan 782.4 Mbps N/A N/A
lossy 69.8 Mbps N/A N/A
wan 83.8 Mbps N/A N/A

Summary

iroh-quinn is 28.8% slower on average

Copy link
Copy Markdown
Collaborator

@flub flub left a comment

Choose a reason for hiding this comment

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

Seems reasonable to me. IIUC now new incoming datagrams remain queued in the kernel's buffers for the socket now instead of being put into our memory while the driver is still alive. This is probably desirable.

Copy link
Copy Markdown
Collaborator

@divagant-martian divagant-martian left a comment

Choose a reason for hiding this comment

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

LGTM.

Excited to finally be able to modify this behaviour

@divagant-martian divagant-martian added this pull request to the merge queue Feb 13, 2026
Merged via the queue into main with commit c51afae Feb 13, 2026
36 checks passed
@divagant-martian divagant-martian deleted the Frando/stop-driver-on-close branch February 13, 2026 15:11
@github-project-automation github-project-automation bot moved this from 🚑 Needs Triage to ✅ Done in iroh Feb 13, 2026
ramfox pushed a commit to n0-computer/iroh that referenced this pull request Feb 14, 2026
## Description

Based on #3879 
Depends on n0-computer/noq#426

With n0-computer/noq#426 the
quinn::EndpointDriver stops once the quinn::Endpoint is closed and all
connections are drained. Thus we don't need the `RwLock` around the
`quinn::Endpoint` anymore.

See [this
thread](#3879 (comment))
for details.

* Add `Endpoint::closed`, which returns a `CancellationToken` that is
cancelled once the endpoint is closing
* Document watcher behavior with regards to closing the endpoint
* Fix test

## Notes & open questions

* Instead of returning a `CancellationToken` we could make this an
`async fn`, however to me it looks quite useful to get a
`CancellationToken` and be able to use
`tokio::spawn(endpoint_closed.run_until_cancelled_owned(async move { ..
})))`
* The cancellation token is cancelled when `Endpoint::close` *starts*,
not when it *ends*. I wasn't sure what expected behavior is here. I
opted for start because this guarantees that the endpoint is fully
usable until then.
ramfox pushed a commit to n0-computer/iroh that referenced this pull request Feb 14, 2026
## Description

Based on #3879 
Depends on n0-computer/noq#426

With n0-computer/noq#426 the
quinn::EndpointDriver stops once the quinn::Endpoint is closed and all
connections are drained. Thus we don't need the `RwLock` around the
`quinn::Endpoint` anymore.

See [this
thread](#3879 (comment))
for details.

* Add `Endpoint::closed`, which returns a `CancellationToken` that is
cancelled once the endpoint is closing
* Document watcher behavior with regards to closing the endpoint
* Fix test

## Notes & open questions

* Instead of returning a `CancellationToken` we could make this an
`async fn`, however to me it looks quite useful to get a
`CancellationToken` and be able to use
`tokio::spawn(endpoint_closed.run_until_cancelled_owned(async move { ..
})))`
* The cancellation token is cancelled when `Endpoint::close` *starts*,
not when it *ends*. I wasn't sure what expected behavior is here. I
opted for start because this guarantees that the endpoint is fully
usable until then.
ramfox pushed a commit to n0-computer/iroh that referenced this pull request Feb 17, 2026
## Description

Based on #3879 
Depends on n0-computer/noq#426

With n0-computer/noq#426 the
quinn::EndpointDriver stops once the quinn::Endpoint is closed and all
connections are drained. Thus we don't need the `RwLock` around the
`quinn::Endpoint` anymore.

See [this
thread](#3879 (comment))
for details.

* Add `Endpoint::closed`, which returns a `CancellationToken` that is
cancelled once the endpoint is closing
* Document watcher behavior with regards to closing the endpoint
* Fix test

## Notes & open questions

* Instead of returning a `CancellationToken` we could make this an
`async fn`, however to me it looks quite useful to get a
`CancellationToken` and be able to use
`tokio::spawn(endpoint_closed.run_until_cancelled_owned(async move { ..
})))`
* The cancellation token is cancelled when `Endpoint::close` *starts*,
not when it *ends*. I wasn't sure what expected behavior is here. I
opted for start because this guarantees that the endpoint is fully
usable until then.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: ✅ Done

Development

Successfully merging this pull request may close these issues.

4 participants