skip to content

Nothing is emitted on a Server-Sent Events stream for twenty minutes and clients quietly vanish — what does an idle stream need?

level: middleimportance: should knowfreq 50%

answer

  1. silence looks like death
  2. write something harmless on a timer
  3. a comment, not an event
  4. roughly fifteen seconds, by suggestion
  5. also bounds time-to-discovery of a departure

basics

~20 s

A periodic comment line: bytes a conforming client ignores and that dispatch no event. The event-stream specification's authoring notes suggest roughly every fifteen seconds, because a quiet connection gets dropped and a silent emitter never notices.

solid answer

~50 s

An idle event stream is indistinguishable from a broken one, to everything on the path and to the emitting side itself. The remedy is to keep writing something harmless: a **comment line**, which a conforming client discards without dispatching anything to the application. The specification's authoring notes suggest one every fifteen seconds or so, precisely because quiet connections get dropped after a short idle period. It is a recommendation to authors, not a protocol requirement, and a client cannot rely on receiving one. It also buys a second thing the specification does not advertise: because detection of a departed receiver rides the write path, a regular write gives you a bounded time to discovery instead of waiting for the next real event. It is not the `retry` field, which sets the client's reconnect delay and does nothing for a response that is currently open.

code

http · 13 lines
http
HTTP/1.1 200 OK
Content-Type: text/event-stream
Cache-Control: no-cache

event: stage
data: {"stage":"soak","targetC":1240}

: keep-alive

: keep-alive

event: stage
data: {"stage":"cool","targetC":900}

go deeper

for a junior

Recall the plain fact: on a stream with nothing to report, the server still writes a comment line every so often, and the application never sees it.

for a middle

Explain the mechanics — a comment dispatches no event, the fifteen-second figure is an authoring suggestion, and the emit loop waits on the source with a timeout so the quiet is bounded.

for a senior

Show the second motive: writes are how a departed receiver is discovered, so the comment interval is also the bound on how long a subscription outlives its viewer.

for a principal

Worth weighing at fleet scale: a few bytes per interval per open response is a continuous write volume, so the interval is a deliberate choice against discovery latency.

## Silence is the hazard A fourteen-hour firing reports a stage change every few minutes and says absolutely nothing in between. From outside the process, those quiet stretches look exactly like a hung server: the response is open, no bytes are moving, and nobody on the path can tell the difference between "nothing has happened" and "nothing will ever happen again". The emitting side's answer is to stop being silent. Write something that costs nothing and means nothing. ## What it writes - **A comment line** — a line the event-stream grammar defines as ignorable, carrying no field and dispatching no event. (Its exact spelling is part of the format itself; the duty to send one periodically is the emitting side's.) - **Nothing reaches the application.** No handler fires, no counter moves, no `data` is delivered. That is the property that makes it safe to send on a timer. - **Nothing about it is addressed to the client's behaviour.** It does not set a delay, does not identify a position in the feed, and does not acknowledge anything the client sent. ## How often, and how strongly the specification says it | claim | strength | |---|---| | send a comment on an idle stream | an authoring note — a recommendation, not a requirement | | roughly every fifteen seconds | the interval the note suggests | | a client may assume one is coming | no: a conforming client must work without it | | the interval is negotiable with the client | no mechanism exists for that | This MUST-versus-suggestion distinction matters in an interview. A candidate who says "the spec requires a heartbeat every fifteen seconds" has promoted an authoring note to a protocol rule and, worse, implied a client may depend on one. The honest statement is: nothing on the wire obliges you, and you should do it anyway. ## The two things it actually buys 1. **It keeps the path warm.** The stated reason for the note is that a quiet connection is liable to be dropped after a short idle period by something in between. Fifteen seconds is comfortably under the intervals that do that. (What an intermediary does to a long-lived response, and how to configure around it, is a separate subject.) 2. **It bounds time-to-discovery of a departed receiver.** A one-way response gives the emitting side no inbound signal, so a receiver that left is usually discovered when a write fails. On a stream that writes every fifteen seconds, that discovery is bounded by fifteen seconds. On the kiln stream without comments, the next write might be twenty minutes away — and until then the emitting side happily keeps a subscription alive for a viewer who closed the page. The second reason is the one that survives even in a deployment with nothing in between, which is why "only an intermediary makes this necessary" is a weak answer. ## What it is not - **It is not the reconnect delay.** The field that tells a client how long to wait before re-opening applies to a response that has already ended; it does nothing for one currently open. Confusing the two is the most common error on this material. - **It is not an application-level heartbeat.** Sending a real event with an empty or dummy payload does keep the path warm, but it dispatches an event, so every client now has to recognise and discard it. The comment exists to avoid exactly that tax. - **It is not a liveness probe with a reply.** Nothing comes back. A duplex protocol can send a probe and expect an answer; a one-way response has no channel for one. - **It is not a substitute for bounding how long the response lives.** A stream can be diligently kept alive for fourteen hours and still be a response held open longer than is wise. ## The operational shape In practice the emit loop waits on the source with a timeout rather than waiting indefinitely. When the source produces an event, write and flush it. When the wait times out, write and flush a comment instead. That single change gives you both properties at once — the stream is never quiet for longer than the timeout, and the write path is exercised on the same cadence — and it costs a handful of bytes per interval per open response. That cost is worth stating out loud at scale: a few bytes every fifteen seconds is nothing per viewer and is a real, continuous write volume across many thousands of open responses, which is one more reason the interval is a choice rather than a constant handed down by the protocol.

  • Does the specification require the periodic comment?
    No. The event-stream section carries it as an authoring note: send a comment every fifteen seconds or so, because connections are liable to be dropped after a short quiet period. It is a recommendation the emitting side owns, and a conforming client must work correctly whether or not one ever arrives.
  • Does an idle comment surface to the receiving application?
    No. It dispatches no event, so no application handler runs and nothing appears in the feed. That is the whole reason to use a comment rather than a dummy event, which every client would then have to recognise and filter.
  • If nothing sits between the two ends, is the comment still worth sending?
    Yes, for the second reason: discovery of a departed receiver rides the write path. Writing every fifteen seconds bounds how long a subscription can outlive the viewer who asked for it; on a stream silent for twenty minutes, that dead weight persists for twenty minutes.

Someone holding a phone line open with nothing to report says "still here" every so often. It carries no information, and it is the only thing keeping either end from assuming the line went dead.

saying these in an interview costs you the question

  • Thinks the periodic comment is delivered to the application as an event.
  • Says the retry field keeps a currently open stream alive.
  • Treats fifteen seconds as a protocol requirement clients can depend on.
  • Sends a dummy event as a heartbeat and makes every client filter it.
  • Assumes a silent stream is healthy because nothing has errored.
  • Expects a reply to the keep-alive on the same response.