Skip to content

Cap channel CIDs at 100 when calling getSyncHistory#6420

Open
VelikovPetar wants to merge 1 commit intodevelopfrom
bug/limit_max_cids_for_sync_develop
Open

Cap channel CIDs at 100 when calling getSyncHistory#6420
VelikovPetar wants to merge 1 commit intodevelopfrom
bug/limit_max_cids_for_sync_develop

Conversation

@VelikovPetar
Copy link
Copy Markdown
Contributor

@VelikovPetar VelikovPetar commented May 6, 2026

Goal

The getSyncHistory endpoint enforces a server-side limit on the number of channel_cids it accepts. When users have a large number of active channels, the SDK was forwarding the full list, which could lead to failed sync requests.

Note: Aligns with the iOS limit set in: GetStream/stream-chat-swift#3863

Implementation

In SyncManager.performSync, cap the cids list at 100 (SYNC_MAX_CIDS) before passing it to chatClient.getSyncHistory. Both code paths (with and without rawLastSyncAt) use the capped list.

UI Changes

No UI changes.

Testing

  • New unit test performSync caps channel_cids at 100 in SyncManagerTest verifies that when 150 cids are passed in, only the first 100 reach getSyncHistory.

Summary by CodeRabbit

  • Bug Fixes

    • Improved sync performance by capping the maximum number of channels synchronized per operation. This prevents potential issues when applications have large numbers of channels to synchronize, ensuring more consistent and reliable behavior across different scenarios.
  • Tests

    • Added test validation to ensure proper enforcement of the channel synchronization limit during sync operations.

Co-Authored-By: Claude <noreply@anthropic.com>
@VelikovPetar VelikovPetar added the pr:bug Bug fix label May 6, 2026
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 6, 2026

PR checklist ✅

All required conditions are satisfied:

  • Title length is OK (or ignored by label).
  • At least one pr: label exists.
  • Sections ### Goal, ### Implementation, and ### Testing are filled (or ignored for dependabot PRs).

🎉 Great job! This PR is ready for review.

@VelikovPetar VelikovPetar changed the title Cap channel CIDs sent to getSyncHistory at 100 Cap channel CIDs at 100 when calling getSyncHistory May 6, 2026
@VelikovPetar VelikovPetar added pr:improvement Improvement and removed pr:bug Bug fix labels May 6, 2026
@VelikovPetar VelikovPetar marked this pull request as ready for review May 6, 2026 17:24
@VelikovPetar VelikovPetar requested a review from a team as a code owner May 6, 2026 17:24
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 6, 2026

SDK Size Comparison 📏

SDK Before After Difference Status
stream-chat-android-client 5.82 MB 5.82 MB 0.00 MB 🟢
stream-chat-android-ui-components 11.02 MB 11.02 MB 0.00 MB 🟢
stream-chat-android-compose 12.37 MB 12.38 MB 0.00 MB 🟢

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 6, 2026

Walkthrough

The PR introduces a hard limit of 100 channel IDs during sync operations. SyncManager.performSync now caps the input channel list using take(SYNC_MAX_CIDS) before passing it to getSyncHistory in both sync branches. A test validates that 150 input IDs are reduced to 100.

Changes

Sync Channel ID Capping

Layer / File(s) Summary
Constraint Definition
stream-chat-android-client/src/main/java/io/getstream/chat/android/client/internal/state/sync/internal/SyncManager.kt (lines 80–81)
New private constant SYNC_MAX_CIDS = 100 defines the maximum channel IDs for sync operations.
Core Sync Logic
stream-chat-android-client/src/main/java/io/getstream/chat/android/client/internal/state/sync/internal/SyncManager.kt (lines 307–312)
performSync caps input cids to 100 via take(SYNC_MAX_CIDS) and passes the capped list to both getSyncHistory calls (rawLastSyncAt and lastSyncAt branches).
Test Validation
stream-chat-android-client/src/test/java/io/getstream/chat/android/client/internal/state/internal/SyncManagerTest.kt (lines 73, 227–246)
New test performSync caps channel_cids at 100 provides 150 channel IDs and asserts that only the first 100 are passed to getSyncHistory via Mockito eq matcher.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Poem

🐰 A hundred channels is the cap today,
No more, no less—we trim the fray.
The sync runs swift with bounded cheer,
And tests confirm this limit clear!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and specifically describes the main change: capping channel CIDs at 100 when calling getSyncHistory, which matches the primary implementation in the changeset.
Description check ✅ Passed The description includes Goal, Implementation, and Testing sections addressing the template requirements. Testing explains the new unit test coverage. UI Changes section confirms no changes.
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.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch bug/limit_max_cids_for_sync_develop

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 and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
stream-chat-android-client/src/test/java/io/getstream/chat/android/client/internal/state/internal/SyncManagerTest.kt (1)

227-246: ⚡ Quick win

Cover the raw-last-sync branch in the cap test too.

This test proves capping for the Date overload, but not for the String (rawLastSyncedAt) overload that was also changed.

Proposed test addition
+    `@Test`
+    fun `performSync caps channel_cids at 100 when rawLastSyncedAt exists`() = runTest(testDispatcher) {
+        /* Given */
+        val nowDate = Date(currentTime)
+        val rawNowDate = streamDateFormatter.format(nowDate)
+        _syncState.value = SyncState(
+            userId = user.id,
+            activeChannelIds = emptyList(),
+            lastSyncedAt = nowDate,
+            rawLastSyncedAt = rawNowDate,
+            markedAllReadAt = nowDate,
+        )
+        val cids = (1..150).map { "messaging:channel-$it" }
+        val expectedCids = cids.take(100)
+
+        whenever(chatClient.getSyncHistory(any(), any<String>())) doReturn TestCall(
+            Result.Success(emptyList()),
+        )
+
+        val syncManager = buildSyncManager()
+
+        /* When */
+        syncManager.performSync(cids = cids)
+
+        /* Then */
+        verify(chatClient).getSyncHistory(eq(expectedCids), eq(rawNowDate))
+    }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@stream-chat-android-client/src/test/java/io/getstream/chat/android/client/internal/state/internal/SyncManagerTest.kt`
around lines 227 - 246, Add a sibling test that verifies capping when calling
the String overload of performSync (rawLastSyncedAt) — create the same 150 cids,
take the first 100 as expectedCids, mock chatClient.getSyncHistory to return a
TestCall(Result.Success(emptyList())), call syncManager.performSync(cids = cids,
rawLastSyncedAt = "<some-timestamp-string>") and verify
chatClient.getSyncHistory was invoked with eq(expectedCids) and
eq("<some-timestamp-string>"); reuse the existing setup (null sync state,
repositoryFacade.selectSyncState returning null, buildSyncManager()) and mirror
the existing test named `performSync caps channel_cids at 100` but target the
rawLastSyncedAt overload.
stream-chat-android-client/src/main/java/io/getstream/chat/android/client/internal/state/sync/internal/SyncManager.kt (1)

307-311: ⚡ Quick win

Emit a warning when channel_cids are truncated.

The cap is correct, but truncation is currently silent; a warning here helps explain missing sync coverage when users have >100 active channels.

Proposed tweak
         val cappedCids = cids.take(SYNC_MAX_CIDS)
+        if (cids.size > SYNC_MAX_CIDS) {
+            logger.w {
+                "[performSync] cids truncated: requested=${cids.size}, capped=${cappedCids.size}"
+            }
+        }
         val result = if (rawLastSyncAt != null) {
             chatClient.getSyncHistory(cappedCids, rawLastSyncAt).await()
         } else {
             chatClient.getSyncHistory(cappedCids, lastSyncAt).await()
         }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@stream-chat-android-client/src/main/java/io/getstream/chat/android/client/internal/state/sync/internal/SyncManager.kt`
around lines 307 - 311, The code silently truncates cids to SYNC_MAX_CIDS before
calling getSyncHistory (cappedCids vs cids), so add a warning when cids.size >
SYNC_MAX_CIDS: emit a log.warn in SyncManager (near the cappedCids calculation)
that includes the original cids size, SYNC_MAX_CIDS, and optionally the
truncated cids (cappedCids) to make missing sync coverage visible; keep existing
call to chatClient.getSyncHistory(cappedCids, rawLastSyncAt ?:
lastSyncAt).await().
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In
`@stream-chat-android-client/src/main/java/io/getstream/chat/android/client/internal/state/sync/internal/SyncManager.kt`:
- Around line 307-311: The code silently truncates cids to SYNC_MAX_CIDS before
calling getSyncHistory (cappedCids vs cids), so add a warning when cids.size >
SYNC_MAX_CIDS: emit a log.warn in SyncManager (near the cappedCids calculation)
that includes the original cids size, SYNC_MAX_CIDS, and optionally the
truncated cids (cappedCids) to make missing sync coverage visible; keep existing
call to chatClient.getSyncHistory(cappedCids, rawLastSyncAt ?:
lastSyncAt).await().

In
`@stream-chat-android-client/src/test/java/io/getstream/chat/android/client/internal/state/internal/SyncManagerTest.kt`:
- Around line 227-246: Add a sibling test that verifies capping when calling the
String overload of performSync (rawLastSyncedAt) — create the same 150 cids,
take the first 100 as expectedCids, mock chatClient.getSyncHistory to return a
TestCall(Result.Success(emptyList())), call syncManager.performSync(cids = cids,
rawLastSyncedAt = "<some-timestamp-string>") and verify
chatClient.getSyncHistory was invoked with eq(expectedCids) and
eq("<some-timestamp-string>"); reuse the existing setup (null sync state,
repositoryFacade.selectSyncState returning null, buildSyncManager()) and mirror
the existing test named `performSync caps channel_cids at 100` but target the
rawLastSyncedAt overload.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: b37245ad-02f6-468e-b8bb-9891953cddfb

📥 Commits

Reviewing files that changed from the base of the PR and between 75cafde and 8dbc9cb.

📒 Files selected for processing (2)
  • stream-chat-android-client/src/main/java/io/getstream/chat/android/client/internal/state/sync/internal/SyncManager.kt
  • stream-chat-android-client/src/test/java/io/getstream/chat/android/client/internal/state/internal/SyncManagerTest.kt

@sonarqubecloud
Copy link
Copy Markdown

sonarqubecloud Bot commented May 6, 2026

Quality Gate Failed Quality Gate failed

Failed conditions
71.4% Coverage on New Code (required ≥ 80%)

See analysis details on SonarQube Cloud

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

Labels

pr:improvement Improvement

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant