WebSocket closed by edge after ~5-7s (code 1006) regardless of keepalive — region ams1
rvfrankena
HOBBYOP
a day ago
Setup
-
Django + Channels app on ASGI, served by gunicorn with a uvicorn ASGI worker. WebSocket endpoint: /ws/backstage/
-
Reached two ways, same result both times:
(a) via a Cloudflare custom domain: staging.razzonanz.com
(b) straight against the raw Railway domain (Cloudflare bypassed): razzonanz-staging-production.up.railway.app
-
Edge region: ams1 (response header: x-railway-edge: ams1)
Symptom
- The WebSocket handshake succeeds (HTTP 101). The connection then closes after ~5-7 seconds with close code 1006 (no close frame), very consistently.
- Three consecutive runs from an external client: closed at 7.1s, 5.2s, 5.2s.
What we have already ruled out
- Not idle/silent: the server sends a keepalive JSON frame to the client every 2s, and the client sends a ping every 3s. So there is continuous traffic in both directions. The keepalive frames keep arriving right up until the drop, and the drop still happens.
- Not the app or the worker: we also tried uvicorn ws_ping_interval and client-side pings, no change. The identical app + client holds a WebSocket open 45s+ with no drop when run locally (no Railway edge in the path).
- Not Cloudflare: bypassing Cloudflare and connecting directly to the *.up.railway.app domain shows the same ~5-7s drop.
- Not a transient incident: this persists after the July 2 US-region edge incident was resolved, and our edge is ams1 (EU), not a US region.
Question
- This looks like the Railway edge terminating WebSocket connections after a short window (~5-12s) in ams1, independent of keepalive or active traffic.
- Is there an idle or absolute timeout on WebSocket connections at the edge? Is it configurable per service?
- Is there a recommended setup to keep long-lived WebSockets stable on Railway (worker type, upgrade handling, headers)?
Happy to share full client logs or a minimal repro on request.