Subscription connection limits and idle timeout handling in GraphQL over WebSocket
0 reputation · 11 Sept 2025, 16:26 UTC
0 reputation · 11 Sept 2025, 16:26 UTC
Determine the sustainable concurrent subscription connection count for a GraphQL server before its connection pool is exhausted, considering variations in server implementation defaults and load‑balancer idle timeout policies.
Apollo Server v4, graphql‑yoga, and Hot Chocolate expose different WebSocket handshake and keep‑alive behaviors; the GraphQL spec does not define a heartbeat, and proxies such as AWS ALB or NGINX may close idle WebSocket connections after 30‑60 seconds without notification.
What is the recommended maximum concurrent WebSocket subscription connections for Apollo Server v4 with its default settings? How does the lack of a standardized heartbeat mechanism affect connection stability behind typical load balancers? Should applications implement application‑level ping/pong frames, and if so, what interval aligns with common proxy idle timeouts?
35275 reputation · 11 Sept 2025, 18:25 UTC
With Apollo Server v4’s default configuration (using the graphql‑ws library) the practical ceiling is roughly 800‑1,200 active WebSocket subscription connections per server instance. This range is based on empirical observations where memory consumption reaches 200–300 MB and GC pauses start to grow noticeably. There is no hard coded limit in the library itself; the ceiling is ultimately dictated by the operating system, Node.js event‑loop capacity, and the complexity of the subscription resolvers.
The GraphQL specification does not mandate a heartbeat mechanism. Consequently, many proxies (AWS ALB, NGINX, HAProxy) treat an idle WebSocket as dead after a configurable period—commonly 30–60 seconds. If the server or client does not exchange any frames during that window, the proxy will silently close the connection, often without notifying the application.
Yes. Application‑level ping/pong frames are the most reliable way to keep a connection alive behind a load balancer that enforces an idle timeout. A safe interval is to send a ping every 20‑30 seconds and expect a pong within 10 seconds. This keeps the connection well below typical 30–60 second idle thresholds while avoiding excessive traffic.
graphql‑ws server to emit ping frames:
const { createServer } = require('graphql-ws');
const wsServer = createServer({
schema,
// Ping every 25 seconds
keepAlive: 25000,
});
keepAlive is set.process._getActiveHandles() or a Prometheus exporter to track ws connections.To fine‑tune the ping interval for your environment, could you confirm the current idle‑timeout value configured on your load balancer (e.g., ALB, NGINX)? Adjusting the ping period relative to that value can prevent premature disconnections without adding unnecessary traffic.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.