Skip to content

The web UI no longer falls back to long polling (T-468) - #337

Merged
chasers merged 1 commit into
mainfrom
liveview-no-longpoll-fallback
Sep 14, 2026
Merged

The web UI no longer falls back to long polling (T-468)#337
chasers merged 1 commit into
mainfrom
liveview-no-longpoll-fallback

Conversation

@chasers

@chasers chasers commented Sep 13, 2026

Copy link
Copy Markdown
Owner

Tracker: T-468.

Root cause, reproduced on a laptop sleep. The rejoin after wake logged WebSocket is closed before the connection is established. That is phoenix.js's replaceTransport closing the still-connecting WebSocket when the longPollFallbackMs: 2500 timer expires while Wi-Fi is still coming back. The tab then runs on long polling until a full page load (the Network panel showed /live/longpoll; the sessionStorage key was null because phoenix.js only memorizes the fallback for a tab whose WebSocket never passed a health check). A long-poll session is a server process on the pod that first answered and exits after 15 seconds without a poll, so every later sleep woke to 410 Gone, which the client raises as a transport error while the transport still counts as open, and LiveView shows as "Something went wrong!". Nothing reaches the server log, since an idle shutdown is a normal exit. With three web pods and no session affinity, every poll also depended on a two-second PubSub hop to the owning pod.

The change. longPollFallbackMs is removed from the LiveSocket options in assets/js/app.js. A tab stays on the WebSocket and phoenix.js keeps retrying a slow open. The /live/longpoll route stays on the server for a client that asks for it explicitly.

What operators see change. A proxy or network that blocks WebSockets now shows the reconnect flash instead of degrading quietly, so the load balancer in front of the web pods must pass WebSocket upgrades. A wake-up still shows the flash for the seconds the WebSocket takes to reconnect; that is a real reconnect, and its wording is the closed #336, to revisit separately.

mix precommit and mix ci green; the bundle builds.

🤖 Generated with Claude Code

https://claude.ai/code/session_01NBmgYoYciJzbcxNYA9Z4d6

…nnot demote a tab to a transport that dies on the next sleep (T-468)

Root-caused from a laptop-sleep reproduction: the console line "WebSocket is
closed before the connection is established" on the rejoin (_mounts=1) is
phoenix.js's replaceTransport closing the still-connecting WebSocket when the
2.5-second longPollFallbackMs timer expires while Wi-Fi is coming back. The tab
then runs on long polling until a full page load (the fallback is memorized in
sessionStorage only when the WebSocket never passed a health check, which is
why the key was null while the Network panel showed /live/longpoll). A long-poll
session is a server process on the pod that first answered; it exits after 15
seconds without a poll, so every later sleep woke to 410 Gone, which phoenix.js
raises as a transport error while the transport still counts as open, which
LiveView shows as the server-error flash "Something went wrong!" — with nothing
in the server log, since an idle shutdown is a normal exit. Three web pods
without session affinity added a two-second PubSub hop to every poll.

app.js drops longPollFallbackMs: a tab stays on the WebSocket and phoenix.js
keeps retrying a slow open. The /live/longpoll route stays on the server for a
client that asks for it. The deployment note says what an operator sees change:
a network that blocks WebSockets now shows the reconnect flash instead of
degrading quietly, so the load balancer must pass WebSocket upgrades.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NBmgYoYciJzbcxNYA9Z4d6
@chasers
chasers merged commit f3c1fb6 into main Sep 14, 2026
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant