Skip to content

ShapeStream replay suppression can discard data messages #4722

Description

@joshdchang

Versions

  • Client: TypeScript, 1.5.23 and 1.5.24; also reproducible on current main at 4051e0fd
  • Electric: not server-version-specific; reproduced with a deterministic ShapeStream fetch mock using valid Shape responses

Bug description

When electric_up_to_date_tracker contains a recent cursor for a shape, a fresh ShapeStream enters replay mode. If the cached response contains change messages followed by an up-to-date control message with that same cursor, ReplayingState requests suppression and ShapeStream.#onMessages returns before publishing anything from the batch.

The next live response can advance the cursor and publish an up-to-date control message without repeating the snapshot rows. Consumers therefore observe an up-to-date stream whose local projection is missing rows that were present in the suppressed cached batch.

This is deterministic with the following response sequence:

  1. Seed the tracker with cursor-1 for the shape.
  2. Return a cached batch containing [insert(row), up-to-date] and electric-cursor: cursor-1.
  3. Return a live batch containing only [up-to-date] and electric-cursor: cursor-2.
  4. The subscriber receives the second up-to-date message but never receives row.

The negative control, using the exact same first response without a tracker entry, delivers both the row and up-to-date message normally.

Expected behavior

Replay handling should suppress only the duplicate cached up-to-date control message. Every data message in that batch must still be delivered to stream subscribers, and the fresh up-to-date message should be delivered once the cursor advances.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions