Build1 distinct publisher3 min readPublished
A dev.to post walks through what happens when Wi-Fi dies mid-session, and the useful part is the asymmetry it exposes: the server can probe with protocol pings, while browser code has to invent its own.
The Engineer · Build desk

Compiled by The EngineerSomething wrong?How this is made
Nothing in the path fires an event, and that is the whole difficulty. The post's account of the lift is that no clean TCP close handshake occurs and packets simply stop arriving [3], while the server goes on believing the client is connected [5]. A close handler needs a close frame to run. Absent one, liveness is something you have to go and measure [6]. The premise carried over from Part 1, that disconnection is normal and recovery is the feature, gets harder once you accept the disconnect may arrive as silence [1].
Sort the three keep-alive layers the post lists by who can observe them [8]. TCP keepalive is an operating system probe. Protocol PING and PONG are control frames the browser answers by itself, and browser JavaScript is never handed the conversation [12]. Of the three, one is visible to code running in a page [1]. That is why the application-level `{"type":"ping"}` exists: it is the only heartbeat a component in the page can time [14]. It costs a normal application frame per beat instead of a control frame [15], and it is the only route by which the client learns whether the server answered and how long it took, before deciding to show a disconnected state and reconnect [13].
The post's failure condition is that nothing comes back within the expected time [9]. Expected time is where all the engineering lives, and the post does not put a number on it. A heartbeat is answering two questions at once, per the author: is the peer still alive, and will an intermediate proxy stop treating this connection as idle [7]. Those questions have different owners. The idle timeout belongs to whatever load balancer or ingress sits in front of you, and you probably did not pick it. The tolerance for a zombie belongs to your product: how long a presence list is allowed to lie, and how many file descriptors you can afford pinned to users who are gone [4]. Copy an interval out of somebody else's write-up and you are importing their proxy configuration and their patience. Both would have to match yours for the number to transfer.
The Node snippet is honest about its own scope. `ws.ping()` sends the frame, and the pong handler sets `ws.isAlive = true` [11]. There is no timer in it. The code that decides how many missed pongs are fatal, clears the flag, and terminates the socket is left for you, and that is the part that either reclaims the descriptor or does not.
In my context both directions run, as separate mechanisms with separate jobs. Server to client, protocol pings, because they are built into the protocol rather than layered on top of application data [10], and their only job is reclaiming sockets and descriptors [4]. Client to server, application pings, because the interface needs an answer it can see [13]. Presence is the one feature that will report, with total confidence, a user who is standing in a lift.
Ranked by verification strength, evidence, and original report placement.
The dev.to post "WebSocket Engineering - Part 2" states that Part 1 reached the conclusion that WebSocket disconnecting is normal and reliable recovery is the feature.
The post describes a class of connection failure that does not announce itself: no close frame, no goodbye, no clean error, with the other side simply disappearing.
In the post's example a user connected over Wi-Fi walks into a lift and the Wi-Fi disappears instantly; sometimes there is no clean TCP close handshake and packets simply stop arriving.
After such a failure the server may still hold the socket, userId, subscriptions, rooms, presence, memory and file descriptor for the vanished client.
The post calls this a zombie connection: the server thinks the client is connected while in reality the client has disappeared.
The post concludes that listening for ws.on("close", ...) is not enough, because sometimes nobody tells you the connection is dead and you have to discover it yourself.
Distinct publishers with included, body-backed reporting in this cluster.
dev.to
1 article · September 1, 2026
Follow any of these and your For You feed starts watching them — no settings page required.
build
The WebSocket That Lies: Why Liveness Detection Beats Reconnect Logic1 distinct publisher
build
Proptech AI pilots stall at the read path out of the system of record1 distinct publisher
build
Next.js 16.3's memory claim didn't reproduce; its TypeScript handoff cut a build by two thirds1 distinct publisher
build
A receipt intent written before dispatch turns an SMS timeout into a poll instead of a resend1 distinct publisher
Evidence-backed comparisons of source perspectives and observed adoption signals. Read the methodology
Which Builder, Operator, and Investor concerns the observed source mix emphasized—not a truth score.
Evidence, demonstrated adoption, hype gap, incentives, and confidence are assessed independently, each on its own current evidence. How these are measured.
Checkable, but uncorroborated
Everything in this story comes from one developer's walkthrough on dev.to — no protocol document cited, no packet capture, no second account, no timing measurement anywhere. What keeps it above guesswork is the character of the assertions: the browser's silence on ping/pong and the shape of the ws API are the sort of thing a reader confirms in a console before finishing the paragraph, and the code shown is concrete enough to run. The soft spot is the quantitative claim it leans on hardest — that operating-system keepalive may wait hours — which arrives as folklore, without a configuration value behind it.
Nothing being shipped
There is no adoption to measure. Nobody released, deployed or benchmarked anything here; ws, React, Cloudflare and Nginx appear as illustrations in a diagram, not as choices made in production with numbers attached. A heartbeat pattern this old has plenty of real-world uptake, but none of it is documented in what we have.
Undersold, and unfinished
The unusual thing about this one is the direction of the mismatch. A silently vanished client that leaves the server holding a file descriptor and a presence entry is a production hazard with a body count, and dev.to presents it as a personal aha — "I used to think heartbeat meant..." — then breaks off before delivering the intermediary-timeout half of the argument. The claims never outrun the evidence; the framing sells the finding short.
Series momentum, nothing sold
A numbered instalment on a developer blog has one obvious motive, and it is Part 3: the piece opens by calling back to Part 1 and closes by setting up infrastructure sitting between browser and server. Beyond audience, there is nothing on the table — no vendor, no sponsorship, no product, no benchmark to win. ws gets named the way a carpenter names a chisel.
Sound as far as it goes
We would stand behind the asymmetry at the heart of this story — server can probe with control frames, browser code cannot, so the application layer has to carry the heartbeat — because it matches how the browser API is specified and the piece is internally consistent about it. Confidence stops where the prose does: no thresholds, no cleanup path, one author, and a final argument left hanging.