Summary
.cat --follow and .last --follow don't observe the caller's interrupt signal. When the consumer of a follow stream is cancelled (for example, an http-nu SSE client disconnects), the reader thread stays parked in rx.blocking_recv() until the next frame matching its topics arrives. On a quiet topic that can be indefinitely.
Where
cross-stream 0.14.0:
src/nu/commands/cat_command.rs, the follow branch (around line 170): rx.blocking_recv() inside a ListStream built with Signals::empty()
src/nu/commands/last_command.rs, lines 95–99: the same pattern
The comment says the consumer dropping the ListStream cancels the producer. But the consumer only gets to drop it after blocking_recv() returns, which needs a frame.
Impact
http-nu 582503c ("release a streaming request's thread when its client disconnects") now interrupts a request's job when its client goes away. For handlers that use .cat --follow, the thread is still held until a matching frame wakes the follower. Streams following rare topics can hold a thread for the life of the server.
Repro
http-nu c7383e2 (cross-stream 0.14.0), with a handler whose SSE stream follows .cat --follow -T "seat.verdict,here,here.list", on an 8-core box:
|
threads |
| before |
18 |
| 20 SSE streams open |
78 |
| 3s after all 20 clients disconnect, no new frames |
38 (one parked follower per stream) |
| 0.5s after appending a single matching frame |
18 |
The release happens only when a matching frame arrives.
Suggested fix
Have the follow branches of .cat and .last observe the caller's interrupt, for example by building the ListStream with engine_state.signals() and waiting on the channel in short slices (such as 100ms) with a check of signals.interrupted() between them. That's the approach http-nu 582503c took for .bus sub. Disconnected followers would then be released within about 100ms, whatever the traffic.
Summary
.cat --followand.last --followdon't observe the caller's interrupt signal. When the consumer of a follow stream is cancelled (for example, an http-nu SSE client disconnects), the reader thread stays parked inrx.blocking_recv()until the next frame matching its topics arrives. On a quiet topic that can be indefinitely.Where
cross-stream 0.14.0:
src/nu/commands/cat_command.rs, the follow branch (around line 170):rx.blocking_recv()inside aListStreambuilt withSignals::empty()src/nu/commands/last_command.rs, lines 95–99: the same patternThe comment says the consumer dropping the
ListStreamcancels the producer. But the consumer only gets to drop it afterblocking_recv()returns, which needs a frame.Impact
http-nu
582503c("release a streaming request's thread when its client disconnects") now interrupts a request's job when its client goes away. For handlers that use.cat --follow, the thread is still held until a matching frame wakes the follower. Streams following rare topics can hold a thread for the life of the server.Repro
http-nu
c7383e2(cross-stream 0.14.0), with a handler whose SSE stream follows.cat --follow -T "seat.verdict,here,here.list", on an 8-core box:The release happens only when a matching frame arrives.
Suggested fix
Have the follow branches of
.catand.lastobserve the caller's interrupt, for example by building theListStreamwithengine_state.signals()and waiting on the channel in short slices (such as 100ms) with a check ofsignals.interrupted()between them. That's the approach http-nu582503ctook for.bus sub. Disconnected followers would then be released within about 100ms, whatever the traffic.