How does a stage that fails when the gap between consecutive values grows too long differ from one bounding the whole sequence?
answer
- which clock resets on a value
- liveness check versus total budget
- steady but slow trips neither gap bound
- failing terminates, it does not skip
- keep-alives make silence meaningful
basics
~20 sA per-gap bound restarts on every value, so a slow but steady source never trips it and it fires only during silence. A whole-sequence bound fires at a fixed age regardless of progress, even while values are still flowing.
solid answer
~40 sThe two measure different clocks. A per-gap bound watches the interval since the last value: each arrival resets it, so a source producing steadily every few seconds can run for hours untouched, and the bound fires only when the source goes quiet for longer than the limit. A whole-sequence bound starts once and fires at its deadline whatever the source is doing, which is what you want when the consumer has a fixed budget for the entire sequence. Both terminate with a failure signal rather than skipping a value: downstream receives no further values, the subscription ends, and upstream is cancelled. Recovery has to be arranged explicitly.
code
pseudocode · 18 linesfunction fail_on_gap(source, maxGap):
out = new_stream()
timer = schedule_after(maxGap, expire)
function expire():
out.fail(GapExceeded)
cancel_subscription(source)
on source value v:
cancel(timer)
out.emit(v)
timer = schedule_after(maxGap, expire)
on source end:
cancel(timer)
out.end()
return outgo deeper
Recall which clock resets: a per-gap bound restarts at every value, a whole-sequence bound starts once and runs to its deadline.
Explain that firing delivers a terminal failure, ends the subscription and cancels upstream, rather than skipping a value and carrying on.
Show that you size it at the point in the pipeline where it sits, allow for legitimate idle periods, and use keep-alives so silence carries information.
Decide what the platform promises: liveness on a feed, a budget on a sequence, or both, and who is paged when each one fires.
## Two different clocks Both stages fail a sequence on time, but they start their clocks differently. - **A per-gap bound** measures the interval since the previous value. Every arrival cancels the pending failure and starts the measurement again. It is a **liveness** check: it asserts that the source keeps making progress, without saying anything about how long the whole sequence may run. - **A whole-sequence bound** starts when the sequence starts and fires at its deadline no matter how many values have arrived. It is a **budget**: it asserts that the whole thing is over by a certain point, without caring whether progress was steady. They are not substitutes, and each leaves exactly the hole the other covers. | | per-gap bound | whole-sequence bound | |---|---|---| | clock starts | at every value | once, at the start | | survives | a slow but steady source, for any length of time | a burst of activity followed by a long silence, until the deadline | | catches | a source that has gone quiet | a sequence that runs longer than its budget | | false alarm when | the source is legitimately idle between bursts | the sequence is long-running by design | ## What failing actually means The word "timeout" makes people think of skipping. Neither stage skips. When the bound fires: 1. A **failure signal** is delivered downstream, which is a terminal event: no further values follow it on that sequence. 2. The **subscription ends**, and upstream is cancelled, so the source is told to stop producing. 3. **Any recovery is something you added** - a fallback value, a fallback source, a resubscription. Without it, the consumer simply sees the sequence end in failure. That makes the bound a fairly blunt instrument. It is right where a stalled sequence is genuinely unusable and the consumer needs to be told so, and wrong where a long gap is merely uninteresting. ## Legitimate silence The hardest part of a per-gap bound is that silence is ambiguous: a source that has died and a source with nothing to say look identical from downstream. A dial nobody touches for three hours produces exactly the pattern a dead feed produces. Two ways out, and they compose: - **Size the bound above the longest legitimate idle period.** Simple, but if that period is long the bound detects nothing useful. - **Have the source emit a periodic keep-alive value.** This is what makes silence meaningful: the feed now promises a value at least every K, so a gap longer than K means something really is wrong. Downstream must recognise the keep-alive and not mistake it for a reading. ## Beware what upstream stages do to the gaps A per-gap bound measures the gaps *at the point in the pipeline where it sits*, and clock-driven stages upstream of it reshape exactly that distribution: - A quiet-period stage upstream emits once per burst, so the gaps the bound sees are the gaps *between bursts* - far longer than the raw source's. Sizing the bound against raw arrival rates will fire on a perfectly healthy feed. - A grouping stage upstream emits once per closed group, so the gaps are group-closing intervals. - A delay upstream shifts everything equally and leaves the gaps unchanged, which is why it is the one clock-driven stage that is safe to ignore here. So place the bound deliberately and size it against the sequence at that point, not against the source at the head of the pipeline. ## Choosing Ask what the consumer's complaint would be. "This feed has died and nobody told me" is a liveness question and wants a per-gap bound, usually paired with keep-alives. "This must be finished by then, whatever state it is in" is a budget question and wants a whole-sequence bound. A sequence that is both critical and long-running can carry both, and they will report different things: one that the source stopped, the other that the work overran.
- What does the subscriber see when a per-gap bound fires?A failure signal, which is terminal: no further values arrive on that sequence, the subscription ends and upstream is cancelled. The bound does not skip the late value and resume. Any fallback value, alternative source or resubscription is something you added explicitly around it.
- A dial nobody touches for hours is legitimate silence - what does that do to a per-gap bound?It makes it fail a healthy feed, because a dead source and an idle one look identical downstream. Either size the bound above the longest legitimate idle period, or have the source emit a periodic keep-alive so the feed promises a value at least every K and a longer gap really does mean trouble.
- A quiet-period stage sits directly upstream of a per-gap bound - what must you check?That the bound is sized against the gaps at its own position, not at the source. The upstream stage emits once per burst, so the gaps arriving at the bound are the intervals between bursts, which are far longer than the raw arrival gaps. Sizing on raw rates will fire on a healthy feed.
saying these in an interview costs you the question
- Thinks the bound skips the late value and continues the sequence
- Believes a per-gap bound also limits the sequence total duration
- Sets the gap bound below the source normal idle period
- Assumes the bound makes a slow producer produce faster
- Sizes the bound on raw source rates despite a reducing stage upstream