When Your WebSocket Lies to You by Saying Nothing
The worst kind of bug is the one your system doesn't report.
A connection is open. No errors. No retries. No alerts. And somewhere in your data, there's a three-hour hole you only find out about later, if you're lucky enough to look at the data at all.
This is the failure mode that logs actively hide from you, because from the transport layer's point of view, nothing went wrong.
The Connection Is Not the Feed
When you establish a WebSocket connection to a market data provider, you're getting a TCP connection that stays alive. But a live connection and a live feed are two different things. A feed can stop, the exchange pauses publishing, the upstream aggregator stalls, a topic partition falls silent, and your socket will just sit there, open and patient, waiting for messages that never arrive.
Your ping/pong heartbeat will still fire. Your reconnect logic will never trigger. Your health dashboard will show green.
The silence looks exactly like normal quiet.
Why Logs Can't Catch This
Logs are event-driven. They record things that happen. A silent WebSocket doesn't produce events, it produces the absence of events. If your monitoring is built on top of log lines and error callbacks, it is structurally blind to this class of failure.
The only thing that can catch a gap is something that looks at the data itself and notices when it stops arriving. You need a different kind of check: one that runs on time, not on events. Something like: "I expected to see at least one trade tick in this market in the last 60 seconds. Did I?"
If the answer is no, that's your alert, regardless of what the WebSocket reports.
The Gap Is Worse in Multi-Market Systems
If you're subscribed to one market, you might notice the silence if you're watching closely. If you're subscribed to 40 or 400 markets, individual feed stalls become nearly invisible. Some markets are legitimately quiet for stretches. Low-volume pairs can go minutes without a trade. Distinguishing "genuinely no trades" from "the feed died" requires baseline knowledge of expected activity per instrument, which means your monitoring has to be symbol-aware, not just connection-aware.
This is where naive implementations fall apart at scale. A global "is the socket alive" check is not sufficient. You need per-symbol heartbeat windows calibrated to each market's normal cadence.
Finding It in the Data
The fact that the gap in the original post was found in the data, not in the logs, is the key observation. The data told the truth. The infrastructure stayed quiet.
This is actually an argument for treating your stored stream as the source of ground truth, not your runtime metrics. Periodically querying your own data for unexpected gaps, running something like a completeness check against expected event density per time window, can surface problems that no alert would have caught in real time.
It's a form of retrospective monitoring that complements live observability. Neither alone is enough.
What Robust Feed Monitoring Actually Looks Like
There are a few patterns that help here:
Event-rate watchers per symbol. Track messages per symbol per rolling window. Alert if any symbol drops below its floor for longer than its threshold.
Sequence gap detection. Many exchanges include a sequence number in feed messages. A jump in that number means you missed messages even if the connection never dropped.
Synthetic heartbeat injection. Some teams publish a known synthetic event into the stream at regular intervals, a canary tick, so that the absence of that event is unambiguous signal of a stalled feed.
Data completeness jobs. A periodic batch job (every 5 or 15 minutes) that audits the last window of stored data for gaps can catch things that live alerting misses, especially for low-frequency symbols.
The Real Lesson
The WebSocket being open is a necessary condition for receiving data. It is not a sufficient condition. Building your reliability model around connection state alone is a category error, you're measuring the pipe, not the water.
Market data infrastructure is hard to get right precisely because the failure modes are quiet. The connection stays up. The system stays running. And somewhere in a database table, a gap accumulates that will eventually matter, to a model, a trade, a backtest, or an audit.
The data always knows before the logs do.
Top comments (0)