Files
suaveplan/packages/api-stack/api/api-ws-bun/src/reconnect/event-buffer.md
2026-05-27 23:29:53 +01:00

3.2 KiB

event-buffer

Purpose

Provides the per-(tenant, topic) reconnect-event buffer used to replay events to a reconnecting client whose lastEventId precedes the current head. Two concrete implementations ship — MemoryReconnectEventBuffer for single-host deployments and BrokerReconnectEventBuffer for broker-backed multi-host fan-out — and resolveReconnectEventBuffer picks the right one according to the configured strategy and the broker wired into the host.

This module is the operating-default pin for design doc §14 open question on buffer storage: the foundation ships "auto" which resolves to broker-backed when a Redis broker is wired, in-memory otherwise.

Features

  • Strategy enum ("auto" | "memory" | "broker") with three documented behaviours.
  • MemoryReconnectEventBuffer is a per-bucket ring buffer — FIFO eviction, limit events per (tenant, topic) pair.
  • BrokerReconnectEventBuffer maintains a local mirror so replay still works during transient broker downtime; pushes also flow to the broker on a fire-and-forget topic for peer-host mirrors.
  • "broker" strategy refuses boot with WS_BUN.RECONNECT_BUFFER_MISS when no buffer-capable broker is wired.

Usage: Basic

import { MemoryReconnectEventBuffer } from "@suaveplan/api-ws-bun";

const buf = new MemoryReconnectEventBuffer<{ value: number }>(64);
buf.push({ id: "1", topic: "orders", tenant, payload: { value: 1 } });
buf.push({ id: "2", topic: "orders", tenant, payload: { value: 2 } });
const replay = buf.since(tenant, "orders", "1");
console.log(replay.length); // 1

Usage: Advanced

import {
    resolveReconnectEventBuffer,
    isBufferCapableBroker,
} from "@suaveplan/api-ws-bun";

const buffer = resolveReconnectEventBuffer("auto", broker, 256);
// If `broker.supportsReconnectBuffer === true`, returns a
// BrokerReconnectEventBuffer wrapping `broker`. Otherwise returns
// MemoryReconnectEventBuffer.
console.log(isBufferCapableBroker(broker)); // true | false

API Reference

  • BufferedEvent<Payload> — { id, topic, tenant, payload }.
  • ReconnectEventBuffer<Payload> — { push, since, dispose }.
  • BufferCapableBroker<Payload> — broker contract extension flagging buffer support.
  • isBufferCapableBroker(broker): boolean — discriminant.
  • MemoryReconnectEventBuffer<Payload> — single-host implementation.
  • BrokerReconnectEventBuffer<Payload> — broker-backed wrapper.
  • resolveReconnectEventBuffer(strategy, broker, limit) — factory.

Implementation Notes

The memory buffer uses Array.prototype.shift() for eviction because the typical limit is small (default 256 events per (tenant, topic) pair), so the O(n) shift is dwarfed by the network cost of a single broadcast. A linked-list ring would micro-optimise the eviction at the cost of opaqueness; the simple array form keeps the code one screenful tall.

The broker wrapper performs void this.broker.publish(...) rather than awaiting because the buffer's contract guarantees push is synchronous — the caller is on the broadcast hot-path and cannot block on broker latency. Peer-host mirror sync is therefore best-effort; deployments that need strict mirror consistency configure "broker" against a stronger backend.