Sequencing & replay

How sequence numbers, gap detection, and paginated replay guarantee no missed events.

Every data frame carries a per-channel sequence so you can prove you received every event in order — and recover exactly the ones you missed after a disconnect. This is the machinery behind Drazill’s no missed fills guarantee.

The frame shape

Each event Drazill pushes is a JSON frame with a fixed envelope:

1{
2 "type": "order_filled",
3 "channel": "user:018f-you",
4 "data": { "order_id": "018f…", "status": "FILLED", "fill_quantity": "10.00", "": "" },
5 "ts": 1767225600.123,
6 "sequence": 42
7}
  • sequence is a monotonic per-channel counter (assigned by a Redis INCR, not a database lock, so a hot market never serializes). It increases by exactly 1 per event on that channel.
  • correlation_id may also be present, tying the event back to the request that caused it.

Detect a gap

Track the last sequence you saw per channel. If a live frame arrives with sequence > last_seen + 1, you missed events in between. Do not process the gapped frame yet — request a replay first, then apply the in-order replayed events.

Resync (paginated replay)

Ask the server to replay everything after your last-seen sequence on the affected channels. Replay is paginated, so drain it until has_more is false:

1{
2 "type": "resync",
3 "channels": ["user:018f-you"],
4 "last_seen_sequences": { "user:018f-you": 41 }
5}

The server first sends the missed frames (each flagged "replayed": true), then a summary per channel:

1{
2 "type": "resync",
3 "channels": ["user:018f-you"],
4 "replayed": { "user:018f-you": { "count": 200, "has_more": true, "last_sequence": 241 } }
5}

If has_more is true, send another resync from the new last_sequence (here 241) and repeat until it is false. You can also pass last_seen_sequences on a subscribe frame to replay from a known cursor the moment you (re)subscribe.

Omit a channel’s cursor (or pass nothing) to start live — the server will not replay ancient history. Only send a last_seen_sequences entry when you genuinely want to catch up from a specific point.

What is durably replayable

Not every event survives for replay. Retention is classed per event:

RetentionEventsReplayable after a gap?
CRITICALorder_filled, order_cancelled, wallet_update, trade, market_event, and everything on your private user: channelYes — durably persisted for the retention window
EPHEMERALprice_tick, orderbook_updateBest-effort — may be shed under backpressure; the next tick supersedes it

A missed fill is never lost: it is CRITICAL, so resync will replay it. A missed price tick may not replay — but the next tick carries the current price anyway, so you lose nothing that matters. When in doubt after a long gap on an ephemeral channel, refetch the current state over REST.

The default replay window is 24 hours and each replay page holds up to 200 events. These are server settings (REALTIME_REPLAY_RETENTION_SECONDS, REALTIME_REPLAY_PAGE_SIZE); clients should page until has_more is false rather than assume a fixed page size.