Skip to content

fix(core): stop the channel list querying channels for every message in a channel it excludes - #3069

Draft
renefloor wants to merge 1 commit into
masterfrom
fix/flu-1013-channel-list-refresh-backoff
Draft

renefloor wants to merge 1 commit into
masterfrom
fix/flu-1013-channel-list-refresh-backoff

Conversation

@renefloor

@renefloor renefloor commented Oct 16, 2026 •

Copy link
Copy Markdown
Contributor

Resolves FLU-1013 (sub-ticket of FLU-1012).

When a message.new arrived for a watched channel that wasn't in a StreamChannelListController's items, onMessageNew ran a full refresh() every time. If the list's filter excludes that channel, the refresh can never add it, so a busy channel caused one QueryChannels per message. In a livestream load test (50 bots, ~15 msg/s, list filter excluding the watched livestream channel), both test phones got 429 Too Many Requests within a few bursts.

Fix

Keep the refresh, since it's how a hidden channel comes back on a new message; the server sends no channel.visible in that case. But remember, per channel, when a refresh left the channel out:

  • further messages in it are ignored for 30 s, doubling to a 10 min cap;
  • the backoff for a channel is cleared once it appears in the list, and all backoffs are cleared on connection.recovered;
  • at most one refresh runs per controller, and messages arriving meanwhile share one trailing refresh.

In the load-test scenario that's about 1 query per 30 s → 10 min instead of ~15/s.

How the other SDKs handle this

None of them re-queries the list because of a message event.

  • iOS checks the channel against the query filter (a Core Data predicate) and links it locally, so a channel outside the filter never appears.
  • Android adds the channel locally from state, with no filter check.
  • React Native / JS moves the cached channel to the top locally, with no filter check; this can be turned off with allowNotLoadedChannelPromotionForEvent.

Matching the filter locally isn't possible on v10 because there's no client-side filter matcher. v11 has one (stream_core's Filter<T>.matches); that fix is tracked in FLU-1014.

Tests

Handler tests for the backoff, doubling and cap, connection recovery, hidden channels and the shared refresh. A controller test checks that 50 message.new events for an excluded channel cause exactly one QueryChannels.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes
    • Fixed channel lists repeatedly refreshing when new messages arrive for channels excluded from the current list. Refreshes are now rate-limited with an increasing delay, while channels can still be added to the list when eligible.
    • Channel list refreshes are coordinated to avoid redundant requests, and a recovered connection resets the delay.

…in a channel it excludes

A message.new for a watched channel outside the list refreshed the whole
list every time, so a busy channel the filter excludes caused one
QueryChannels per message and hit the rate limit. Keep the refresh, but
back off per channel once a refresh leaves it out (30 s, doubling to
10 min), and run at most one refresh at a time with one trailing refresh.

Refs FLU-1013

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Oct 16, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 313ec79c-df6e-4115-a04d-0588efd476df
📥 Commits

Reviewing files that changed from the base of the PR and between 6c8cee1 and 842fc74.

📒 Files selected for processing: 5
  • packages/stream_chat_flutter_core/CHANGELOG.md
  • packages/stream_chat_flutter_core/lib/src/stream_channel_list_event_handler.dart
  • packages/stream_chat_flutter_core/pubspec.yaml
  • packages/stream_chat_flutter_core/test/stream_channel_list_controller_message_new_test.dart
  • packages/stream_chat_flutter_core/test/stream_channel_list_event_handler_message_new_test.dart

Included review availability: This review used your included allowance. Your plan provides up to 4 included reviews per hour; 3 remain after this review.

📝 Walkthrough

The channel list handler now throttles refreshes for channels missing from the list. Backoff starts at 30 seconds and doubles up to 10 minutes. Refresh requests are coordinated per controller, and connection recovery clears backoffs.

Changes: Missing-channel refresh flow

Layer / File(s) Summary
Per-controller refresh policy
packages/stream_chat_flutter_core/lib/src/stream_channel_list_event_handler.dart, packages/stream_chat_flutter_core/pubspec.yaml
The handler adds a controller-specific refresher that tracks backoff per channel and coordinates refresh requests. The package adds the clock dependency.
Event handling and verification
packages/stream_chat_flutter_core/lib/src/stream_channel_list_event_handler.dart, packages/stream_chat_flutter_core/test/stream_channel_list_controller_message_new_test.dart, packages/stream_chat_flutter_core/test/stream_channel_list_event_handler_message_new_test.dart, packages/stream_chat_flutter_core/CHANGELOG.md
Message events use the refresher for missing channels. Connection recovery clears backoffs. Tests cover backoff timing, channel changes, concurrent requests, and bursts of messages. The changelog describes the throttling behavior.

Priority: ➖ Normal

Estimated code review effort: 3 (Moderate) | ~25 minutes

Change: Bug fix

Sequence Diagram(s)

sequenceDiagram
  participant StreamChannelListEventHandler
  participant MissingChannelRefresher
  participant StreamChannelListController
  StreamChannelListEventHandler->>MissingChannelRefresher: Request refresh for missing channel
  MissingChannelRefresher->>StreamChannelListController: Request non-resetting refresh
  StreamChannelListController-->>MissingChannelRefresher: Return refreshed channel list
  MissingChannelRefresher->>MissingChannelRefresher: Update backoff from list result
Loading

Suggested reviewers: xsahil03x

Merge Risk: ⚪ Minimal · up to 842fc

No confirmed issue remains that should block merging after normal checks.

Pre-merge checks: Passed 5
Check name Status Explanation
Description Check Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check Passed The title clearly and concisely describes the main change: preventing repeated channel-list queries for every message from an excluded channel.
Docstring Coverage Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check. Docstring coverage is scoped to functions touched by this diff. Analyzed 0 functions across 0…
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.
Full details: Docstring Coverage

Explanation

No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check. Docstring coverage is scoped to functions touched by this diff. Analyzed 0 functions across 0 files. (5 skipped: 5 unsupported.)

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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.

@renefloor
renefloor marked this pull request as draft October 16, 2026 14:25
@codecov

codecov Bot commented Oct 16, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 78.62%. Comparing base (6c8cee1) to head (842fc74).

Additional details and impacted files
@@            Coverage Diff             @@
##           master    #3069      +/-   ##
==========================================
+ Coverage   78.56%   78.62%   +0.05%     
==========================================
  Files         452      452              
  Lines       29451    29482      +31     
==========================================
+ Hits        23139    23180      +41     
+ Misses       6312     6302      -10     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

This branch has not been deployed

No deployments
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