fix: heartbeat is_current_turn false after steer via command() - #5820
fix: heartbeat is_current_turn false after steer via command()#5820Christian-Sidak wants to merge 1 commit into
Conversation
When a steer happens, `_start_turn()` overwrites the durable row's `turn_id` with the new turn before the old turn's next heartbeat fires. The original code compared the durable row's `turn_id` to decide if a lock loss was a cancel vs. a first-beat race. For the steer case, the row already shows the new turn_id, so `turn_was_established` is False and `is_current_turn` stays True -- the old turn thinks it is still current even though it has been displaced. Fix: when `refresh_alive` fails, read the alive lock's current holder directly. If the lock is held by a different turn_id, the old turn was displaced by a steer and `is_current_turn` is set to False. The durable row check (`turn_was_established`) is kept as the fallback for the cancel case (lock absent, row matches). Adds a regression test that drives the real steer write path via `command()` with `force=True` rather than manually simulating the lock cancellation, matching the exact sequence from issue Agenta-AI#5790. Fixes Agenta-AI#5790 Signed-off-by: Christian-Sidak <61099993+Christian-Sidak@users.noreply.github.com>
|
@Christian-Sidak is attempting to deploy a commit to the agenta projects Team on Vercel. A member of the Team first needs to authorize it. |
|
Hi @Christian-Sidak, thanks for opening a pull request. 🙏 This PR was automatically closed because it does not yet meet our contribution requirements:
We ask for this so every change is documented and demonstrably tested before review. How to get it reopened See the Contributing guide and Creating your first PR. If you think this was closed in error, leave a comment and a maintainer will take a look. |
|
Caution Review failedThe pull request is closed. ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (2)
Disabled knowledge base sources:
📝 WalkthroughSummary by CodeRabbit
WalkthroughHeartbeat interruption detection now checks the Redis alive-lock owner before using the durable turn row. A regression test exercises steering through ChangesHeartbeat current-turn detection
Estimated code review effort: 3 (Moderate) | ~20 minutes Possibly related PRs
✨ Finishing Touches 💡 1🛠️ Fix failing CI checks 💡
🧪 Generate unit tests (beta)
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. Comment |
Summary
After a steer (interrupt + new message on a session), the displaced turn's heartbeat kept reporting
is_current_turn: true. Clients polling the old turn had no signal that it had been superseded.Root cause.
heartbeat()used the durable row'sturn_idto disambiguate a lock loss: ifprior_stream.turn_id == request.turn_idthe key being gone meant cancellation; if not, it looked like a first-beat race and was left asis_current_turn=True. A steer calls_start_turn(), which overwrites the durable row'sturn_idwith the new turn before the old turn's next heartbeat fires. So the old turn's beat always saw a "different"turn_idin the row, concluded "first-beat race", and stayedTrue-- even though it had been displaced.Fix. When
refresh_alivefails, read the alive lock's current holder directly viaget_alive_owner. If the lock is held by a differentturn_id, the old turn was displaced by a steer (is_current_turn=False). The durable row check (turn_was_established) is kept as the fallback for the cancel case (lock absent, row still matches our turn).Files changed:
api/oss/src/core/sessions/streams/service.py-- importget_alive_owner, fixis_current_turnlogic inheartbeat()api/oss/tests/pytest/unit/sessions/test_heartbeat_is_current_turn.py-- regression test that goes throughcommand()write pathFixes #5790
Testing
Verified locally
api/oss/tests/pytest/unit/sessions/test_heartbeat_is_current_turn.py(all 5 tests pass)test_command_matrix_inputs_data.py,test_project_scoped_locks.py,test_owner_claim.py,test_heartbeat_ownership.py,test_heartbeat_first_touch_race.pyAdded or updated tests
Added
test_steer_via_command_flips_old_turn_heartbeat_to_not_currenttotest_heartbeat_is_current_turn.py. This test drives the real steer write path viacommand(force=True)-- the exact sequence from the bug report -- rather than manually simulating a lock cancellation. It verifies that after a steer via the command endpoint, the old turn's heartbeat reportsis_current_turn=False.QA follow-up
N/A -- pure coordination-plane logic fix, no user-visible UI or API shape change.
Demo
This is a pure backend coordination-plane fix -- no UI change, no API shape change. The observable behavior change is a correctness fix in a boolean field on an internal heartbeat response.
Test run demonstrating the fix (all 5 tests pass, including the new regression test):
The new test would fail on
main(before this fix) because the old code's durable-row comparison cannot detect the steer displacement.Checklist