A user closes a conversation screen and its message subscription is cancelled — what travels upstream, and when does the source stop?
answer
- values one way, cancel the other
- up the chain, stage by stage
- each stage tears down as it passes
- a request, not a kill
- source stops where it checks
basics
~20 sA cancel request travels up the same chain the values came down: each stage stops asking its upstream, forwards the request and tears itself down. The source stops at the next point where it observes the request, not instantly.
solid answer
~40 sValues flow **downstream**, from source through each stage to the subscriber; cancellation flows the other way. When the screen cancels through its handle, the bottom of the chain marks itself finished and passes the request to the stage above it, which does the same, until it reaches the source. Each stage on the way runs its own cleanup. The source then stops producing and releases whatever it opened — but only where it actually checks, so cancellation is a request, not a kill: a value already handed to the chain may still surface, and work already dispatched may run to completion unless the source can abort it. Two things break the chain: a stage that swallows the request instead of forwarding it, and a source that never looks between emissions.
code
pseudocode · 12 linesfunction messageSource(conversationId, subscriber):
connection = openConnection(conversationId)
subscriber.onCancel(function() {
connection.close() // the request is observed here
})
while connection.hasNext() and subscriber.isActive():
subscriber.emit(connection.next())
if subscriber.isActive():
subscriber.complete() // nothing is signalled after a cancelgo deeper
Hold on to the direction: values travel down the chain to you, and your cancel travels back up it to the source. Cancelling is asking the source to stop, not forcing it.
Explain the walk up the chain: each stage stops asking its upstream, runs its own teardown and forwards the request, until the source observes it and releases what it opened.
Diagnose the two breaks: a stage that absorbs the request while the source keeps running, and a source that never checks between emissions. Both show up as resources that never fall.
Treat abandonability as a design property: if a pipeline cannot be cancelled end to end, request timeouts and shutdowns become resource leaks rather than recoveries.
## Two directions on one chain A subscription is a two-way structure, and this is the fact the question is really testing. Values move **downstream**: source, then each stage in order, then the subscriber. Cancellation moves **upstream**: subscriber, then each stage in reverse order, then the source. Both directions run along the links created when the subscription was established, which is why cancelling is possible at all — the chain remembers who is above it. When the screen closes and cancels through its handle: 1. The bottom of the chain marks itself **no longer active**, so late values it receives are dropped rather than delivered to a screen that is gone. 2. It tells the stage above it to stop, and that stage stops asking its own upstream for more. 3. Each stage runs whatever teardown it owns on the way past — a stage holding a timer cancels the timer, a stage holding a buffer drops it. 4. The request reaches the source, which stops producing and releases what it opened. ## Cancellation is a request, not a kill Nothing in this mechanism reaches into the source and stops it mid-instruction. The source stops **where it next observes the request**, and that has consequences a working engineer is expected to name: - **A value already in flight may still be delivered.** It was emitted before the request arrived; the chain below simply drops it. - **Work already dispatched may finish anyway.** If the source handed a request to something that cannot be aborted, cancelling the subscription stops the *delivery* of the result, not the work. - **No terminal signal is owed afterwards.** Once a subscriber cancels, it has asked to stop hearing; it is not promised a completion or failure signal to confirm the stop. - **The stop is not instantaneous.** A source in a tight producing loop that never checks between emissions will keep emitting into a chain that is discarding everything. | Aspect | Values | Cancellation | |---|---|---| | Direction | Downstream, source to subscriber | Upstream, subscriber to source | | Who starts it | The source | The subscriber, or a stage acting on its behalf | | Timing guarantee | Delivered one at a time | Observed at the source's next check | | Ends the run | Only a terminal signal does | Yes, from the subscriber's side | ## The two ways propagation fails The chain only works if every link honours it, so two failure shapes dominate in real pipelines. **A stage that does not forward the request.** A stage that keeps its own upstream subscription — because it is serving several downstream subscribers, or because it holds a buffer it wants to drain — can absorb the cancel. The subscriber stops hearing values immediately, which makes the screen look correct, while the source keeps producing and keeps its resources open. The symptom is a connection count that never falls even though every screen closed cleanly. **A source that never checks.** A source that emits in a loop with no check between emissions cannot observe the request until the loop ends. It keeps burning work that is thrown away downstream. Sources written to be cancellable check their active flag between emissions and register a hook that closes what they opened the moment the request arrives. ## Why the direction matters in practice Because cancellation is the only way work started by a subscription stops early, the upstream path is what makes a reactive pipeline safe to abandon. A request whose client disconnects, a screen that closes, a race between several sources where the losers must stop — all of them are expressed as one cancel travelling up one chain, releasing each stage's resources on the way. A pipeline in which one stage is careless about forwarding it is a pipeline you cannot abandon, and that shows up as resource exhaustion rather than as a visible bug. In an interview, state the direction first, then the cooperation, then the failure modes. Candidates who describe cancellation as something the source pushes downstream have the model backwards, and everything they derive from it — when cleanup runs, why a stage matters, what the subscriber is owed — comes out wrong too.
- Why might a stage that serves several downstream subscribers refuse to forward the cancel?Because its upstream run is shared. One subscriber leaving does not mean the others have, so the stage decrements its count of interested subscribers and only cancels upstream when the count reaches zero. The trade-off is that a bug in that accounting keeps the source running with nobody listening.
- After cancelling, the screen still receives one message. Is that a defect?Not in itself. Cancellation is observed asynchronously, so a value emitted before the request arrived can still be in flight. The defect is delivering it into a destroyed screen: the subscriber must mark itself inactive on cancel and drop what arrives afterwards.
saying these in an interview costs you the question
- Says the source pushes the cancellation downstream to subscribers
- Claims cancelling stops in-flight work immediately
- Expects a completion signal to confirm that the cancel took effect
- Assumes every stage automatically forwards the request upstream
- Thinks a source in a tight loop is stopped by the runtime