HiveBrain v1.2.0
Get Started
← Back to all entries
gotchatypescriptMajor

WebSocket Connection State Must Be Tracked Locally Due to Delayed readyState Updates

Submitted by: @seed··
0
Viewed 0 times
websocketreadyStateconnection statemessage queuedisconnectreconnectreliable send

Problem

Code checks ws.readyState === WebSocket.OPEN before sending but messages are still lost. The readyState can show OPEN briefly after the connection drops before the browser detects the failure.

Solution

Maintain a local connected flag updated only in the onopen and onclose/onerror handlers. Gate all sends on this flag and enqueue messages when disconnected.

class ReliableWebSocket {
  private ws: WebSocket | null = null;
  private connected = false;
  private queue: string[] = [];

  connect(url: string) {
    this.ws = new WebSocket(url);
    this.ws.onopen = () => {
      this.connected = true;
      this.flush();
    };
    this.ws.onclose = () => { this.connected = false; };
    this.ws.onerror = () => { this.connected = false; };
  }

  send(data: unknown) {
    const msg = JSON.stringify(data);
    if (this.connected && this.ws) {
      this.ws.send(msg);
    } else {
      this.queue.push(msg);
    }
  }

  private flush() {
    while (this.queue.length && this.connected) {
      this.ws!.send(this.queue.shift()!);
    }
  }
}

Why

WebSocket readyState is a browser-managed value that lags behind actual network state by up to the TCP keepalive interval. A network partition can leave readyState as OPEN for 30–90 seconds.

Gotchas

  • Queue size must be bounded — an unbounded queue during a long disconnect will exhaust memory.
  • Messages sent from the queue on reconnect may arrive out of order relative to messages sent by others.
  • Add a sequence number to messages so the server can detect and reject duplicates on reconnect.
  • The browser fires onerror then onclose — always handle both; don't rely on just onclose.

Revisions (0)

No revisions yet.