skip to content

A yard system pushes position updates over a WebSocket faster than the cabin console consumes them - what in the protocol tells the sender to slow down?

level: seniorimportance: must knowfreq 58%

answer

  1. look for the signal, find none
  2. the layer below is the only brake
  3. several buffers before anything is felt
  4. a queue grows and nothing fails
  5. stale data, not dropped data

basics

~20 s

Nothing at the WebSocket layer. The protocol defines no credit, window or acknowledgement a receiver can use to say stop. The only backpressure is TCP's underneath, and it reaches the sending application as a growing outbound queue rather than an error.

solid answer

~40 s

The WebSocket protocol has no application-level flow-control signal at all: a receiver cannot ask for less, a sender is never told a message was consumed, and no message carries a credit or an acknowledgement. The only real backpressure lives one layer down. When the receiving application stops reading, its kernel receive buffer fills, its advertised TCP window closes, the sender's kernel send buffer fills, and only then do the sending application's writes stop draining. In the sender's process that appears as an outbound queue growing with no error raised and a connection that still looks healthy - so the observable failure is memory on the sender and stale data at the receiver. What to do about it is a policy the application has to choose; the protocol contributes nothing to that choice.

go deeper

for a junior

Know that the protocol offers no way for a receiver to ask a sender to slow down. Handing a message to the connection always appears to succeed, whether or not the other side can keep up.

for a middle

Explain the chain: the receiver stops reading, its buffer fills, its TCP window closes, the sender's buffer fills, and only then do the sender's writes stop draining - several buffers after the problem began.

for a senior

Show the diagnosis. The signature is a growing outbound queue with no errors, prompt liveness answers, and data that is correct but stale, and you must know the protocol supplies no signal that would have warned you.

for a principal

The absence is why a policy must exist and be chosen deliberately at the producing end. A system that hands every message to the socket has picked unbounded buffering and unbounded staleness without deciding to.

## The protocol's own answer is: there is no signal WebSocket gives you framing, a liveness probe, a negotiated name and a close handshake. It does not give you flow control. There is no credit scheme, no receive window at the message layer, no acknowledgement, and no message a receiver can send that means *send less*. A sender is never told that a message was delivered, let alone consumed, so it cannot pace itself on anything the protocol reports. This is less an oversight than a division of labour - and it is the most consequential absence in the protocol, because it turns a transport question into an application design. ## Where the backpressure actually lives A WebSocket runs over TCP, and TCP does have flow control. The chain, in order: 1. The receiving **application** stops reading from its socket, because it is busy rendering, parsing, or writing to something slow. 2. Its kernel **receive buffer** fills, because nothing is draining it. 3. Its TCP stack **advertises a smaller window**, eventually zero, so the peer's stack stops putting bytes on the wire. 4. The sending side's kernel **send buffer** fills. 5. Only now does the sending **application** feel anything: its writes stop completing. The important property of that chain is how late and how indirectly step 5 arrives. Megabytes of buffering sit between the receiver's decision to stop reading and the sender's first hint that anything is wrong, and by then the data at the head of the queue is already old. ## What the sender actually observes - **An outbound queue that grows.** The messages the application handed over are held somewhere - in its own process, in the kernel - and that memory is the sender's. - **No error.** Nothing fails, nothing reports a problem. Handing a message over succeeds whether or not it will ever be delivered. - **A healthy-looking connection.** Liveness probes are small and are answered promptly, because answering one does not require the receiver to consume the backlog. A connection can look perfectly alive while being hours behind. - **Staleness rather than loss.** The receiver eventually gets every message, including the position update from four minutes ago that it will now render as current. That last point is the one that surprises people: the failure of an unthrottled feed is usually not a dropped message, it is a correct message delivered far too late, plus memory growth on the side that never noticed. ## What the protocol does not decide for you Because the wire offers no signal, every option lives above it: what a sender should do when it produces faster than a consumer drains is an application policy with real tradeoffs - one this leaf deliberately hands on rather than answers. What matters at the protocol level is knowing **why** the decision exists: it exists because there is no message the receiver can send to make it go away. The corollary is that the decision must be made explicitly, at the point where messages are produced. A system that produces at whatever rate its source runs at, and hands every message to the socket, has chosen a policy - unbounded buffering and unbounded staleness - it simply has not chosen it on purpose. ## The version wrinkle worth knowing A WebSocket opened over HTTP/1.1 rides a TCP connection directly, and the chain above is the whole story. A WebSocket bootstrapped over HTTP/2 or HTTP/3 rides a **stream**, and streams do have their own transport flow-control windows. That changes the machinery underneath - a stalled socket can now stall on the stream's window before the connection's - but it does not change the answer: those windows are transport-level and are not surfaced to the WebSocket application either. There is still no message the receiving application can send to ask for less. ## How to talk about it in an interview The strong answer has three moves, in this order: state the absence precisely (no application-visible flow-control signal in the protocol), name the backpressure that does exist and where it lives (TCP, several buffers away), and describe what the sender actually sees (a queue, no error, a healthy-looking connection, stale data). Then say the policy is an application decision. A candidate who says only *use backpressure* has not shown they know the protocol supplies none.

  • Why does the connection still look healthy while the receiver is minutes behind?
    Because liveness is answered by the connection's control path, not by the application's consumption. A probe is small and is answered without touching the backlog, so a socket that is hours behind on data still answers promptly. Liveness proves the peer is reachable; it says nothing about whether it is keeping up.
  • If TCP provides backpressure anyway, why is its absence at the WebSocket layer a problem?
    Because it arrives far too late and in the wrong form. Several buffers' worth of messages are already committed before the sending application feels anything, and what it feels is writes that stop draining rather than a signal it can act on per message. By then the head of the queue is stale and the memory is already spent.
  • Does the absence of a flow-control signal mean messages get dropped?
    No - that is the usual misreading. The connection keeps delivering, so messages arrive eventually and in one piece. The symptoms are memory growth on the sending side and data that is correct but far too old on the receiving side. Dropping is one policy an application may choose; it is not something the protocol does.

A chute from the yard down into the cabin. The yard can keep tipping crates into it for as long as it likes, and nothing in the cabin can call up to say slow down - the only feedback that exists is the chute itself eventually backing up, by which time everything in it is old.

saying these in an interview costs you the question

  • Expects the protocol to apply backpressure automatically
  • Thinks an unconsumed message is dropped by the connection
  • Reads a healthy liveness probe as proof the peer is keeping up
  • Believes a failed write reports the receiver being slow
  • Assumes a delivered message means a processed message