Skip to content

fix(llc): call accept race fix#1258

Open
Brazol wants to merge 2 commits into
mainfrom
fix/call-accept-race
Open

fix(llc): call accept race fix#1258
Brazol wants to merge 2 commits into
mainfrom
fix/call-accept-race

Conversation

@Brazol

@Brazol Brazol commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

Fixes #1254

Summary by CodeRabbit

  • Bug Fixes
    • Fixed an issue where incoming calls could be incorrectly rejected after acceptance due to event timing between WebSocket and HTTP.
    • Improved call acceptance handling by updating call acceptance status optimistically and reverting it if server acceptance fails.
  • New Features
    • Incoming call acceptance now reflects immediately in the UI while the server sync completes in the background.
  • Tests
    • Added coverage for optimistic acceptance, rollback on failure, idempotency, and lifecycle acceptance behavior.
  • Chores
    • Updated the changelog with an Unreleased Fixed entry.

@Brazol Brazol requested a review from a team as a code owner June 15, 2026 11:24
@coderabbitai

coderabbitai Bot commented Jun 15, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: e2f10865-487b-4bae-a965-8ca083d18b77

📥 Commits

Reviewing files that changed from the base of the PR and between 776d71c and 6272a75.

📒 Files selected for processing (2)
  • packages/stream_video/CHANGELOG.md
  • packages/stream_video/test/src/call/call_accept_test.dart
✅ Files skipped from review due to trivial changes (1)
  • packages/stream_video/CHANGELOG.md

📝 Walkthrough

Walkthrough

lifecycleCallAccepted now accepts an accepted flag, and accept() applies the accepted state before awaiting the coordinator response, reverting it on failure. Tests cover the optimistic state change, rollback, retry, and lifecycle transition cases.

Optimistic call acceptance

Layer / File(s) Summary
lifecycleCallAccepted accepts a flag
packages/stream_video/lib/src/call/state/mixins/state_lifecycle_mixin.dart
lifecycleCallAccepted accepts accepted: false and updates acceptedByMe from that value.
Optimistic accept with revert
packages/stream_video/lib/src/call/call.dart
accept() updates local call state before CoordinatorClient.acceptCall() and reverts on failure.
Accept flow tests and changelog
packages/stream_video/test/src/call/call_accept_test.dart, packages/stream_video/CHANGELOG.md
Tests cover optimistic acceptance, failure rollback, retry behavior, and lifecycle transition handling; the changelog adds the unreleased fixed note.

Sequence Diagram(s)

sequenceDiagram
  participant UI as UI
  participant Call as Call.accept()
  participant State as lifecycleCallAccepted
  participant Coord as CoordinatorClient
  participant WS as Coordinator event handling

  UI->>Call: accept()
  Call->>State: lifecycleCallAccepted()
  Call->>Coord: acceptCall(cid)
  Note over WS: call.accepted event may arrive while HTTP is in flight
  WS->>State: read acceptedByMe=true
  alt coordinator success
    Coord-->>Call: Success
  else coordinator failure
    Coord-->>Call: Failure
    Call->>State: lifecycleCallAccepted(accepted: false)
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 I hopped to accept before the wind could race,
And set the little flag in its proper place.
If the server stumbles, I hop back neat,
With false to undo the prior treat!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description only links issue #1254 and omits the required Goal, Implementation details, Testing, and checklist sections. Add the template sections with a clear goal, implementation summary, testing notes, and checklist items.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly points to the accept() race-condition fix and matches the main code change.
Linked Issues check ✅ Passed The code updates call.accept() and lifecycleCallAccepted() to prevent the race condition described in issue #1254.
Out of Scope Changes check ✅ Passed The changelog and new tests support the bug fix and do not introduce unrelated scope.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/call-accept-race

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.

@coderabbitai coderabbitai 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.

Actionable comments posted: 1

🤖 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.

Inline comments:
In `@packages/stream_video/lib/src/call/call.dart`:
- Around line 906-909: The unconditional rollback on any Failure at line 906 is
too broad and can cause false rejection states. When a transport-level failure
occurs after the server has accepted the call, reverting acceptedByMe to false
via _stateManager.lifecycleCallAccepted(accepted: false) at line 908 can cause
_handleCoordinatorCallAccepted to incorrectly trigger the "accepted on another
device" logic again. Instead of reverting on all Failure results, classify the
error to distinguish between definitive rejections from the server versus
transport-level failures, and only perform the rollback for specific error types
that represent clear non-acceptance outcomes. This ensures that optimistic
acceptance is only reverted when we have definitive evidence the server did not
accept the call.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 2769b017-d45a-48f6-a079-4198e58ef51b

📥 Commits

Reviewing files that changed from the base of the PR and between 879ee25 and 776d71c.

📒 Files selected for processing (2)
  • packages/stream_video/lib/src/call/call.dart
  • packages/stream_video/lib/src/call/state/mixins/state_lifecycle_mixin.dart

Comment thread packages/stream_video/lib/src/call/call.dart
@codecov

codecov Bot commented Jun 15, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 9.68%. Comparing base (879ee25) to head (6272a75).
⚠️ Report is 1 commits behind head on main.

Additional details and impacted files
@@           Coverage Diff            @@
##            main   #1258      +/-   ##
========================================
+ Coverage   9.66%   9.68%   +0.02%     
========================================
  Files        676     676              
  Lines      49689   49690       +1     
========================================
+ Hits        4801    4812      +11     
+ Misses     44888   44878      -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.

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.

Race condition in accept() causes local rejection of incoming calls

1 participant