Skip to content

fix: prevent overlapping group call force rejoins#2406

Open
marco-a-affinidi wants to merge 1 commit into
famedly:mainfrom
marco-a-affinidi:repeated_key_generation
Open

fix: prevent overlapping group call force rejoins#2406
marco-a-affinidi wants to merge 1 commit into
famedly:mainfrom
marco-a-affinidi:repeated_key_generation

Conversation

@marco-a-affinidi

@marco-a-affinidi marco-a-affinidi commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

When GroupCallSession.onMemberStateChanged() observed the local membership disappear while the call was still in entered, concurrent updates could trigger the force-rejoin path more than once before room state caught up. That led to repeated sendMemberStateEvent() and preShareKey() work, which could cascade into redundant key generation and unstable local participant state.

This change extracts the recovery flow into _forceRejoin(), shares a single in-flight rejoin across concurrent callers, and clears the stale local participant cache before awaiting the resend path.

The test coverage was also tightened with focused GroupCallSession regressions that prove both behaviors: stale local state is cleared until room state catches up, and concurrent updates do not start multiple force rejoins.

@cursor

cursor Bot commented Jul 10, 2026

Copy link
Copy Markdown

PR Summary

Medium Risk
Touches group-call membership recovery and key pre-sharing when server/client state diverge; behavior is well covered by new tests but affects live VoIP stability paths.

Overview
When room membership shows the local user left while the session is still entered, onMemberStateChanged used to run the recovery path inline on every concurrent update—repeated sendMemberStateEvent() and preShareKey() and unstable local participant state.

The recovery flow is now _forceRejoin(), guarded by a single _forceRejoinInProgress future so overlapping callers share one rejoin. Before waiting on the resend/key path, the stale local entry is removed from _participants so later updates do not re-trigger force rejoin; on failure while still entered, that participant is restored so a retry can run. Delayed-event canceller cleanup is unchanged in behavior but lives in the helper.

test/group_call_session_test.dart adds regressions for cache clearing, canceller teardown, retry after failure, single concurrent rejoin, and shared failure for waiters.

Reviewed by Cursor Bugbot for commit 71f567a. Bugbot is set up for automated code reviews on this repo. Configure here.

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes using high effort and found 2 potential issues.

Fix All in Cursor

Bugbot Autofix is ON, but it could not run because the branch was deleted or merged before autofix could start.

Reviewed by Cursor Bugbot for commit 4ff45e3. Configure here.

Comment thread lib/src/voip/group_call_session.dart Outdated
Comment thread lib/src/voip/group_call_session.dart Outdated
@marco-a-affinidi
marco-a-affinidi marked this pull request as draft July 10, 2026 09:34
@marco-a-affinidi
marco-a-affinidi force-pushed the repeated_key_generation branch from 4ff45e3 to c243193 Compare July 10, 2026 09:52
@marco-a-affinidi
marco-a-affinidi marked this pull request as ready for review July 10, 2026 09:53
@marco-a-affinidi
marco-a-affinidi force-pushed the repeated_key_generation branch from c243193 to 1b4a047 Compare July 10, 2026 09:54
@codecov

codecov Bot commented Jul 10, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 59.70%. Comparing base (53a6a79) to head (71f567a).

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #2406      +/-   ##
==========================================
+ Coverage   59.62%   59.70%   +0.07%     
==========================================
  Files         161      161              
  Lines       20329    20342      +13     
==========================================
+ Hits        12121    12145      +24     
+ Misses       8208     8197      -11     
Files with missing lines Coverage Δ
lib/src/voip/group_call_session.dart 84.70% <100.00%> (+5.36%) ⬆️

Continue to review full report in Codecov by Harness.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 53a6a79...71f567a. Read the comment docs.

@marco-a-affinidi
marco-a-affinidi force-pushed the repeated_key_generation branch 3 times, most recently from 51ad300 to 94442cb Compare July 14, 2026 07:03
When GroupCallSession.onMemberStateChanged() observed the local membership disappear while the call was still in entered, concurrent updates could trigger the force-rejoin path more than once before room state caught up. That led to repeated sendMemberStateEvent() and preShareKey() work, which could cascade into redundant key generation and unstable local participant state.
This change extracts the recovery flow into _forceRejoin(), shares a single in-flight rejoin across concurrent callers, and clears the stale local participant cache before awaiting the resend path.
The test coverage was also tightened with focused GroupCallSession regressions that prove both behaviors: stale local state is cleared until room state catches up, and concurrent updates do not start multiple force rejoins.
@marco-a-affinidi
marco-a-affinidi force-pushed the repeated_key_generation branch from 94442cb to 71f567a Compare July 17, 2026 08:04
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