Skip to content

perf(llc): skip replaying oversized /sync payloads - #2934

Draft
xsahil03x wants to merge 1 commit into
masterfrom
feat/sync-event-replay-limit
Draft

perf(llc): skip replaying oversized /sync payloads#2934
xsahil03x wants to merge 1 commit into
masterfrom
feat/sync-event-replay-limit

Conversation

@xsahil03x

@xsahil03x xsahil03x commented Sep 3, 2026

Copy link
Copy Markdown
Member

Replaying a large /sync payload through handleEvent holds local persistence and state updates long enough to slow down the regular requests that need them. Payloads over 250 events are no longer replayed — the synced channels are re-queried in their place.

Implements the Sync events limit spec, matching stream-chat-swift (SyncRepository) and stream-chat-android (SyncManager), which use the same 250-event threshold.

Ticket: FLU-756

What changed

  • StreamChatClient.sync skips event replay when a /sync response carries more than 250 events.
  • On reconnect the synced channels are re-queried with queryChannels in their place, one 30-channel page at a time (the server returns at most 30 channels per request, so a single query would silently cover only the first page).
  • lastSyncAt advances only once that refresh succeeded. Dropping the events is safe when their state has been re-fetched; advancing past a failed refresh would lose them.
  • Mark-all-read events from a skipped payload are still applied, since a channel refresh does not carry read state.
  • lastSyncAt fallbacks now use DateTime.timestamp() instead of local time.

Behavior change worth a second look

On reconnect, the re-query after a skipped replay runs even when recoverStateOnReconnect is false (which StreamChatCore sets for every app built on stream_chat_flutter). Skipping replay drops in-memory channel state, so without it there is nothing to repair the currently open channel. When the refresh does run, the flag's own re-query is skipped so the channels are not queried twice.

A direct client.sync() call issues no queries — only the reconnect path opts into the refresh.

Verification

dart analyze --fatal-infos, dart format, and the full stream_chat suite (1632 tests) pass. New tests cover the skip, the re-query in its place, page batching past 30 channels, lastSyncAt being kept when the refresh fails, and mark-all-read surviving the skip.

Replaying a large `/sync` payload through `handleEvent` holds local
persistence and state updates long enough to slow down the regular
requests that need them.

Payloads over 250 events are no longer replayed. On reconnect the synced
channels are re-queried in their place, a page at a time, and `lastSyncAt`
only advances once that refresh succeeded — dropping the events is safe
when their state has been re-fetched, but advancing past a failed refresh
would lose them. Mark-all-read events are still applied, since a channel
refresh does not carry read state.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

Important

Draft PR not reviewed

Draft PRs are not automatically reviewed by default.

  • Trigger a manual review

To automatically review draft PRs, update your CodeRabbit configuration:

reviews:
  auto_review:
    drafts: true

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant