Skip to content

WS broadcast loops use raw ws.send — one closing socket aborts the tick for all subscribers #210

Description

@v1ktorrr0x

Bug

Three WS broadcast loops use raw ws.send() without per-socket error handling. If one socket throws during the loop, the entire iteration aborts and all remaining subscribers miss that tick.

Source

src/routes/ws.ts — three loops: flushPriceUpdate (:436-449), trade.executed listener (:539-549), funding.updated listener (:572-582).

436      for (const client of slabClients) {
437        if (client.ws.readyState === WebSocket.OPEN && ...) {
441          if (client.ws.bufferedAmount > MAX_BUFFER_BYTES) continue;
442          client.ws.send(msg);   // ← raw send; can throw
443        }
444      }

Impact

readyState and bufferedAmount are checked, but the socket can transition to closing in the TOCTOU window before send(), which the ws library throws synchronously. The single outer try/catch then aborts the entire loop — every subsequent subscriber in the iteration misses that price/trade/funding tick.

safeSend() was introduced at ws.ts:223-236 precisely to neutralise this for message-handler sends; the fan-out loops were not converted.

Fix

Replace all three raw client.ws.send(msg) calls with safeSend(client.ws, payloadObject). Since safeSend serializes internally, build the payload object once per channel before the loop rather than pre-serializing.

Verification

Subscribe 3 clients to price:<slab>; force one socket into a half-closed state mid-loop; emit a price.updated event → after fix, the other two still receive the tick.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions