In a two-source join, what happens to the output when one source completes early or emits nothing at all?
answer
- completion is a signal, not an error
- the rule decides what a completion means
- empty queue makes a completion decisive
- a completed slot keeps contributing its last value
- no value from one source means no result
basics
~20 sIt depends on the joining rule. Lockstep pairing ends as soon as a completed source's queue is empty, discarding whatever is buffered elsewhere. Latest-value combination keeps going on the completed source's last value until all sources complete. A source that emits nothing leaves the output empty.
solid answer
~40 sEvery source ends with exactly one terminal signal, and each joining rule turns that signal into a different outcome. Under **lockstep pairing**, a source's completion matters once its queue runs dry: no further pair can form, so the join completes — and values still queued on the other side are dropped without a warning. Under **latest-value combination**, a completed source that has already emitted keeps its last value in its slot, and the remaining sources go on producing results; the output ends only when the last source completes. Under both rules, a source that completes **without ever emitting** makes a result impossible, so the output completes empty — successfully, with no failure to see. That silent empty completion is why an optional input usually gets a starting value before it reaches the join.
code
pseudocode · 17 lines// lockstep pairing: how a completion is handled
on complete from source i:
done[i] = true
if queue[i] is empty:
// no further pair can ever form
discard every other queue
emit complete
// otherwise keep pairing until queue[i] drains
// latest-value combination: how a completion is handled
on complete from source i:
done[i] = true
if filled[i] is false:
emit complete // no result was ever possible
else if every done[k] is true:
emit complete // last source finished
// otherwise latest[i] keeps taking part in resultsgo deeper
Remember that finishing is a normal signal, not an error, and that a source which produced nothing at all still finishes normally. A join that needs one value from every source therefore produces nothing.
Explain the split: pairing ends once a finished source's queue is dry and drops what is buffered elsewhere, while latest-value combination keeps a finished source's last value and runs until the final source ends.
Diagnose the silent stop. Instrument each input's values and terminal signal separately, distinguish an empty result from a still-open silent source, and decide at the boundary what an empty input should mean before it reaches the join.
Set the convention that optional inputs are seeded and that empty means an explicit value rather than silence. Left to each feature, this becomes a recurring class of incident whose symptom is always 'the page stopped updating'.
## What "ending" means for a join A source pushes zero or more values and then produces exactly one terminal signal: a completion or a failure. A join subscribes to several such sources and must produce its own terminal signal for its own subscriber. The rule you picked for combining values also decides how those inbound terminal signals turn into the outbound one — and the rules disagree sharply. The question matters because an early completion is not an error. Nothing logs, nothing throws, and the symptom a user reports is "the screen stopped updating", which looks identical to a hang, a lost connection and a starved worker. ## Rule by rule **Lockstep pairing** (a queue per source, front values consumed together): - A source's completion is only decisive when **its own queue is empty**. While values remain queued for it, pairs can still form and the join keeps emitting. - The moment a completed source's queue runs dry, no further pair can ever form, so the join completes immediately. - Values still sitting in the *other* sources' queues are discarded. They were never paired, so they never reach the output, and nothing reports the loss. **Latest-value combination** (a slot per source, overwritten on arrival): - A completed source that has already emitted **does not end the output**. Its final value stays in its slot and continues to take part in every later result. - The output completes when the **last** source completes, because only then can no further arrival occur. - This is the rule's most useful property: a source that produces one configuration value and finishes is a perfectly good input, and it keeps contributing forever. **Both rules, when a source completes having emitted nothing:** no result can ever be assembled, so the output completes with zero values. This is a success, not a failure — an empty completion is a well-formed answer meaning "there was nothing". ## The two cases side by side | joining rule | one source completes after emitting | one source completes having emitted nothing | |---|---|---| | lockstep pairing | continues while that source's queue still holds values, then completes; other queues are discarded | completes immediately with no results | | latest-value combination | continues on that source's last value until every source has completed | completes immediately with no results | | sequential appending | the completion is the trigger that starts the next source | the next source still runs; the empty source contributes nothing | | first-to-respond selection | the winner's terminal signal becomes the output's | rules differ on whether an empty completion counts as responding — know which you have | ## Predicting and diagnosing it 1. **Name the rule.** The answer to "why did my output stop?" is different for pairing and for latest-value combination, and guessing which one you are looking at wastes the whole investigation. 2. **Observe each input's terminal signal separately.** Attach an observing hook to each source before the join and record its values and its terminal signal. A join that went quiet almost always has one input that completed, and the input that completed is usually the one nobody suspected. 3. **Ask whether the input was empty or merely finished.** A query that matched no rows, a lookup that found nothing, a configuration stream with no entries — all complete empty, and every one of them silences a join that needs a value from each source. ## Designing so it cannot bite - **Give an optional input a starting value** before the join, so its slot or queue is never empty. The join then emits from the first real arrival on the other side rather than waiting for a partner that may never come. - **Prefer latest-value combination when inputs are long-lived state** — configuration, a selected filter, a session — since a source that emits once and completes is naturally accommodated. - **Prefer pairing when each result must correspond to one event from each side**, and accept that the pipeline ends when either side runs out. - **Decide what an empty input should mean** at the boundary rather than inside the join: map the empty case to an explicit default value or to an explicit failure, so the outcome is visible instead of silent. ## The cancellation that follows When a join produces its own terminal signal, it no longer needs its remaining inputs, so it cancels those subscriptions. That matters when those sources were doing real work: an in-flight fetch is abandoned, a connection is closed, and any effect that had not yet happened will not happen. An early completion on one input therefore does not just end the output — it can quietly stop work you believed was running elsewhere.
- A source neither emits nor completes. How does that differ from an early completion?An early completion ends the output, so a subscriber sees a terminal signal and can react. A source that stays open and silent produces nothing at all: the join waits forever, the subscriber sees neither values nor an ending, and only an external deadline or a liveness check will reveal it. Silence is the harder failure because it never resolves.
- Does the join cancel its remaining sources when it terminates early?Yes. Once the join has produced its terminal signal it cancels the subscriptions it still holds. Any work those sources had in flight is abandoned, which is desirable for reads and dangerous for anything with side effects, since a partially applied effect may already have landed.
- How do you stop an optional input from silencing the whole join?Give it a starting value before the join so its slot or queue is never empty — a default, an empty collection, or an explicit 'not available' marker. The join then emits as soon as the required inputs move, and the optional input upgrades the result when it eventually arrives.
saying these in an interview costs you the question
- Says any source completing immediately ends the combined output
- Treats an empty source as a failure the join will report
- Thinks buffered values are flushed when pairing completes
- Believes a completed source stops contributing its last value
- Assumes a silent join must mean a thread or connection problem
- Expects the join to substitute a default for a missing source