(fix) test: Fix KeyError in test_idle_heartbeat with connection repla… - #762
(fix) test: Fix KeyError in test_idle_heartbeat with connection repla…#762mykaul wants to merge 1 commit into
Conversation
|
CI flakiness - unrelated, will send a separate PR. |
6cc6e02 to
ce46f2e
Compare
ce46f2e to
dbdddb8
Compare
|
Warning Review limit reachedNext included review available in 28 minutes. View limit detailsLimit details: You’ve used the included review currently available. You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. Review configuration: ⚙️ Run configurationConfiguration used: Organization UI Review profile: QUIET Plan: Advanced Run ID: 📒 Files selected for processing (1)
📝 WalkthroughWalkthroughThe Possibly related PRs
Suggested labels: Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
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 |
|
Rebased onto current What the Relationship to #653: that PR's review thread flagged this same test's flakiness as a "pre-existing, likely repo-wide intermittent failure," not reproducible locally, possibly triggered by unrelated tests running alongside it — cc @dkropachev @mykaul. Turns out that's exactly right, and traceable to a real mechanism:
So does this fix the #653 root cause? Partially, and it's important to be precise about which part: the primary race (pool warm-up) was already fixed on Testing:
CI: last recorded run (before rebase) was all green; rebase onto current Squashed into a single commit with an updated message covering all of the above. No unresolved review threads existed on this PR (no reviews yet). Force-pushed the rebase + amended commit; kept as draft per the original intent. |
There was a problem hiding this comment.
Pull request overview
Improves test_idle_heartbeat resilience to shard-aware connection replacement races.
Changes:
- Filters validation to snapshotted connections.
- Warns when connections are replaced.
- Fails if no connections remain validatable.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
dbdddb8 to
51d1064
Compare
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 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 `@tests/integration/standard/test_cluster.py`:
- Around line 820-823: Update the assertion message for known_connections so it
accurately states that no snapshotted connection remains in the current
connection list, rather than claiming all connections were replaced. Keep the
existing len(known_connections) > 0 failure condition unchanged.
- Around line 803-810: The reconciliation logic around snapshot_connections must
retain strong references to the original connection objects instead of relying
on integer IDs, preventing ID reuse from misidentifying replacements. Update
missing_from_current, unknown_in_current, and known_connections to compare
connections by identity using is while preserving the existing snapshot and
replacement behavior.
🪄 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: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: d1950f42-e109-4890-8d5a-d432f9bc1edf
📒 Files selected for processing (1)
tests/integration/standard/test_cluster.py
test_idle_heartbeat snapshots each connection's request_ids keyed by id(connection), sleeps for a couple of heartbeat intervals, then looks the connections back up by id() to validate the heartbeats. If a connection object is replaced in between, the lookup raises KeyError. master already fixed the main source of this: wait_for_all_pools() only waits for the first connection per host, so shard-aware connections to the remaining shards could still be opening (and replacing placeholders) during the sleep window. 454f727 and f348637 added _wait_for_all_shard_connections(), called before the snapshot is taken, and deliberately dropped an earlier "skip unknown connections" band-aid so the assertions stay meaningful once the pool is known to be stable. That fix only guarantees connection *count* has stabilized, though. It doesn't rule out an existing connection being swapped for a new object in the same shard slot while the count stays constant: - HostConnection._open_connection_to_missing_shard() replaces a shard's connection once orphaned_threshold_reached, independent of pool size. - HostConnection.return_connection() -> _replace() does the same when a connection is found defunct or closed. Both can fire at any time, including during this test's own sleep, and are more likely to fire under CPU/IO contention (e.g. other tests running concurrently delaying heartbeat responses) - which lines up with the "why does this pop now, and only intermittently" puzzle from the scylladb#653 review discussion (with @dkropachev and @fruch) about this same test's flakiness. Guard against the resulting KeyError by filtering to connections that are still present in the snapshot, but without silently weakening the test: in the common case (no replacement) the filtered list is identical to the full connection list, so behavior is unchanged from master. Only when the filter actually drops something do we log a warning (so a recurrence remains visible in CI) and we still hard-fail if every single connection was replaced, since at that point nothing was validated. Compare both directions of the snapshot/current intersection, not just "every current connection is known". return_connection() has a genuine asynchronous gap: it pops a defunct/closed connection out of the pool's dict synchronously, but the replacement is inserted later by _replace(), which runs on another thread via session.submit(). A snapshot taken during that gap sees fewer current connections than were recorded, and every one of them is still "known" (nothing new has landed yet) - so "all current connections are known" is trivially true even though fewer connections than snapshotted are being validated. Tracking missing-from-current (snapshotted connections no longer present) in addition to unknown-in-current (new connections not in the snapshot) makes that partial-removal case surface as a warning too, per review feedback from @copilot-pull-request-reviewer. Signed-off-by: Yaniv Kaul <yaniv.kaul@scylladb.com>
51d1064 to
666bff8
Compare
Fixes a
KeyErrorintest_idle_heartbeat(tests/integration/standard/test_cluster.py) caused by shard-aware connection replacement racing with the test's connection-identity snapshot.Background:
masteralready fixed the main source of this via_wait_for_all_shard_connections()(added in 454f727 / f348637), which waits for shard pools to reach their full connection count before the snapshot is taken. That closed the common pool-warm-up race, and deliberately reverted an earlier silent "skip unknown connections" band-aid so the test's assertions stayed meaningful.That fix doesn't cover a narrower race:
HostConnectioncan still swap an existing connection object for a new one in the same shard slot without changing the pool's connection count — via_open_connection_to_missing_shard()(onceorphaned_threshold_reached) or viareturn_connection()->_replace()(on a defunct/closed connection). Either can fire during the test's own sleep window, and is more likely under CPU/IO contention (e.g. other tests running concurrently, delaying heartbeat responses).This PR guards against the resulting
KeyErrorby filtering to connections still present in the snapshot, while keeping the test meaningful:master.See PR discussion for more analysis and the connection to the long-standing
test_idle_heartbeatflakiness discussed on #653.Pre-review checklist
./docs/source/.Fixes:annotations to PR description.