A stop no longer waits on blocking work past the drain 529c703db24d
After the 30 s drain, serve returned and logged stopped, but dropping the runtime waited for whatever still ran on its blocking threads: on 2026-10-17 04:07 a restart stood a minute past stopped until systemd killed it, so the hub was down 90 s. The runtime now gets one second (shutdown::finish). Test: a blocking task of 30 s does not hold it. Also pins oxygen with the faster log and clean diff (oxygen#94). Refs #233
- Author
- Andy McCall @andymccall <[email protected]>
- via
- agent
Claude Code <[email protected]> · delegate for changes, until 2026-11-13 19:00Z · key ea5f78160088
- When
- · 2026-10-17 03:20 UTC
- Signature
- ✔ signed by Claude Code
- Hash
529c703db24dc1ee425177acbd16d99050046e4ae6cd949493d6dc83515c0ee5- Depends on
- 2bae995eb2f1 380996db84e5 b210727578e8 c92a99490cba d23464c0ac60
- Depended on by
- 6aedcd6c0ad2
- In bookmarks
- api-unknown-fields cancel-landed-runs diffusion-pin-bookmark draft-ready main oh-comment-body-file proposal-list-fast
- In tags
- v0.6.0 v0.6.1 v0.7.0 v0.8.0 v0.9.0 v0.9.1 v0.9.11 v0.9.15 v0.9.16 v0.9.19 v0.9.2 v0.9.20 v0.9.21 v0.9.22 v0.9.23 v0.9.24 v0.9.3 v0.9.4 v0.9.5 v0.9.6 v0.9.7 v0.9.8 v0.9.9
- Edits
- 5 atoms, 0 tree operations, 3 files
Browse the tree at this change
modified crates/hub/src/main.rs +3 −1
| … | 125 unchanged lines |
||
| 126 | 126 | tune_allocator(); |
|
| 127 | 127 | let rt = tokio::runtime::Builder::new_multi_thread().enable_all().build()?; |
|
| 128 | 128 | rt.spawn(return_freed_memory()); |
|
| 129 | - | rt.block_on(run()) |
|
| 129 | + | let out = rt.block_on(run()); |
|
| 130 | + | oxygenhub::shutdown::finish(rt); |
|
| 131 | + | out |
|
| 130 | 132 | } |
|
| 131 | 133 | ||
| 132 | 134 | /// glibc's allocator gives each thread that allocates an arena of its own |
|
| … | 249 unchanged lines |
modified crates/hub/src/shutdown.rs +26 −0
| … | 12 unchanged lines |
||
| 13 | 13 | /// How long the requests in flight get to finish. |
|
| 14 | 14 | pub const DRAIN: std::time::Duration = std::time::Duration::from_secs(30); |
|
| 15 | 15 | ||
| 16 | + | /// How long, after the drain, work still running on the runtime's |
|
| 17 | + | /// blocking threads (a slow request's repository work, a bucket call) may |
|
| 18 | + | /// hold the process. Dropping the runtime would wait for it however long |
|
| 19 | + | /// it takes: on 2026-10-17 a restart stood a minute past "stopped", until |
|
| 20 | + | /// systemd killed it. |
|
| 21 | + | pub const EXIT_GRACE: std::time::Duration = std::time::Duration::from_secs(1); |
|
| 22 | + | ||
| 23 | + | /// End the runtime once `serve` has returned, cutting off what still runs. |
|
| 24 | + | pub fn finish(rt: tokio::runtime::Runtime) { |
|
| 25 | + | rt.shutdown_timeout(EXIT_GRACE); |
|
| 26 | + | } |
|
| 27 | + | ||
| 16 | 28 | fn sender() -> &'static watch::Sender<bool> { |
|
| 17 | 29 | static STOP: OnceLock<watch::Sender<bool>> = OnceLock::new(); |
|
| 18 | 30 | STOP.get_or_init(|| watch::channel(false).0) |
|
| … | 54 unchanged lines |
||
| 73 | 85 | } |
|
| 74 | 86 | #[cfg(not(unix))] |
|
| 75 | 87 | None |
|
| 88 | + | } |
|
| 89 | + | ||
| 90 | + | #[cfg(test)] |
|
| 91 | + | mod tests { |
|
| 92 | + | /// Blocking work still running when the hub stops does not hold the |
|
| 93 | + | /// process: the runtime ends within its grace. |
|
| 94 | + | #[test] |
|
| 95 | + | fn finishing_does_not_wait_for_blocking_work() { |
|
| 96 | + | let rt = tokio::runtime::Builder::new_multi_thread().enable_all().build().unwrap(); |
|
| 97 | + | rt.spawn_blocking(|| std::thread::sleep(std::time::Duration::from_secs(30))); |
|
| 98 | + | let started = std::time::Instant::now(); |
|
| 99 | + | super::finish(rt); |
|
| 100 | + | assert!(started.elapsed() < super::EXIT_GRACE * 3, "{:?}", started.elapsed()); |
|
| 101 | + | } |
|
| 76 | 102 | } |
replaced deps/oxygenflow +0 −0
No line changes.