NATS remains the default. Existing configurations with a
runtime.ws.jetstream
block still select JetStream, and configurations without it still select NATS
Core for the native gateway.
Redis Streams configuration
Use the shared block when the same engine runs both realtime roles:VS_REALTIME_PROVIDER=redis_streams
and VS_REDIS_URL. Role-specific VS_WS_REDIS_* and
VS_GRAPHQL_REDIS_* variables can override tuning when the roles run in
separate processes.
Redis wire contract
One Redis Stream is used per tenant:
The gateway parses Redis IDs numerically as
(milliseconds, sequence), never
lexically. A wrong-provider, expired, malformed, or ahead cursor is rejected;
it never silently falls back to live-only delivery.
Publishing to Redis
Publish the canonical event envelope with any Redis client. This Node.js example uses the officialredis package:
MAXLEN bounds growth atomically with XADD. The gateway also applies the
configured max_length periodically as a retention backstop for publishers
that omit it. Publishers should still set MAXLEN so retention remains bounded
while gateways are offline.
Scaling model
Redis mode does not run one blockingXREAD per browser. Each gateway process
opens one shared tailer per active tenant and fans live events through a bounded
local broadcast. A reconnecting client reads only its missing range with
XRANGE, up to a captured live watermark, then joins live fan-out without a
replay/live gap.
The tailer retries transient Redis read failures with bounded backoff. After six
consecutive failures it terminates attached sessions explicitly and rejects new
sessions until its last-ID read loop recovers; sockets are not left silently
parked behind a permanently unavailable broker.
This keeps Redis connection count proportional to gateway replicas and active
tenants, not connected clients. Live-only GraphQL operations share a logical
socket source. Resumed GraphQL operations open subject-filtered logical sessions
over the shared tenant tailer so each operation replays independently.
Client cursor contract
New clients should select and persistcursor, then send it only after event
processing succeeds:
connection_init.resume_from_cursor field remains a compatibility
fallback. Prefer resumeFromCursor per operation when multiplexing.
seq and resume_from_seq remain available for existing JetStream clients.
Redis events omit the native numeric seq; GraphQL keeps seq as a string
alias of cursor for schema compatibility.
Production security
- Use
rediss://with server certificate validation outside trusted local networks. - Use a dedicated Redis ACL user limited to the configured stream prefix and
the commands required by the provider:
PING,XREAD,XRANGE,XREVRANGE,XTRIM, and publisher-sideXADDwhere applicable. - Put gateways and publishers on private networks; do not expose Redis to browsers or the public internet.
- Keep
runtime.tenantconfigured. The server-authorized tenant chooses the stream key; clients cannot select another tenant’s stream. - Monitor broker session failures, replay rejection, local fan-out lag, and stream length. A local lag error is terminal so the client reconnects from its last processed cursor instead of continuing across a silent gap.