Skip to main content
VentStream can replay GraphQL subscriptions after a disconnect or operation replacement when the gateway uses JetStream or Redis Streams. Reliability is operation-scoped:
  1. Start the first subscription without a cursor.
  2. Process each event successfully.
  3. Persist that operation’s opaque cursor.
  4. Recreate the operation with resumeFromCursor.
The gateway resumes strictly after that cursor. Multiple operations can share one graphql-transport-ws connection while maintaining independent cursors. This provides at-least-once processing within the broker retention window. Handlers must be idempotent because a disconnect between applying a side effect and saving its cursor can replay the event.
Checkpoint only after every required side effect succeeds. Saving a cursor when the event is merely received can permanently skip unfinished work.

Typed schema contract

Author the subscription normally. resumeFromCursor is a reserved operation argument that VentStream adds to the effective runtime schema. VentStream also adds cursor and seq to an inline result type when those fields are absent:
The effective schema exposed through GraphQL introspection includes:
cursor is provider-neutral. Keep it as a string: JetStream currently emits decimal strings while Redis Streams emits values such as rs:1712345678901-0. For reliability-critical operations, do not author application fields named cursor or seq. Existing schemas that define either name retain their application mapping for backward compatibility, which shadows the corresponding broker checkpoint field.

First connection

The client has no checkpoint on its first subscription. Omit resumeFromCursor or pass null:
No cursor means live-only delivery from the time the operation attaches. It does not request historical events.

Requirements

  • Run the engine with the graphql role and a replay-capable provider: JetStream or Redis Streams.
  • Select cursor and stable event id in every reliability-critical operation.
  • Maintain one cursor store per logical operation and argument scope. An order stream and an audit stream must not overwrite each other’s checkpoint.
  • Use idempotent handlers keyed by event id.
  • Size broker retention for the longest outage plus worst-case catch-up time.
  • Treat RESUME_EXPIRED and INVALID_CURSOR as terminal recovery decisions; never silently clear a bad checkpoint.

Install Apollo

Store cursors per operation

Keep the storage boundary small so browser localStorage can later be replaced with IndexedDB or a backend checkpoint service:
For side effects that change durable business state, store the event ID, side effect, and cursor transactionally whenever possible.

Multiplex operations on one Apollo connection

graphql-ws normally replays an active operation with the variables it had when it was first created. Those variables may contain an old cursor. Therefore the reconnect hook below removes active observers and recreates every operation after the new socket is acknowledged, reading the latest cursor from each store. The getCurrentAccessToken, apply*Idempotently, report*, and readGraphQLErrorCode functions in this example are application-owned integration points. Implement them using your identity provider, durable business store, and telemetry system.
VentStream’s current gateway only requires a non-empty token and trusts the tenant asserted during connection initialization. Put the gateway behind an authenticating proxy that validates the token and binds its claims to the allowed tenant before exposing it to untrusted clients.
The two promise queues preserve processing order independently. An order handler cannot advance the audit cursor, and a slow audit handler does not prevent a successfully processed order from checkpointing. The generation guard drops queued work that has not started when recovery begins. A handler already in progress cannot be cancelled safely, which is why durable side effects still need event-ID idempotency.

Connection cursor compatibility

resume_from_cursor in connection_init remains supported. It is a fallback for clients with one operation or clients that maintain one globally coordinated checkpoint across every operation on the socket. When an operation supplies resumeFromCursor, the operation value takes precedence. For multiplexed applications, prefer operation cursors. They let operations attach at different times without one operation acknowledging another operation’s replay.

Recovery behavior

Production checklist

  • Persist each operation cursor after processing, never before it.
  • Recreate multiplexed operations with fresh cursor variables after reconnect.
  • Make handlers idempotent using event id.
  • Expose connecting, live, recovering, terminal-error, replay-lag, and handler failure states to application telemetry.
  • Test socket termination while publishing and verify every event after each operation’s checkpoint is eventually processed.
  • Test a cursor outside retention and require an explicit rebuild.
  • Size retention for the maximum outage plus worst-case replay time.
See Realtime brokers for provider configuration, cursor semantics, retention, and gateway observability.