fix(zookeeper): make membership reads sequential and resilient - #11338
Conversation
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
Unbounded diagnostic console output remains unresolved; the test-name typo is minor.
Get a fresh assessment by requesting another Copilot review.
Review effort: Lite
Findings: 1
Open (1)
What changed in this PR
Improves ZooKeeper read resilience with scoped retries, session ownership, snapshot fencing, and expanded tests.
Changes:
- Adds Polly retries for connection-loss reads.
- Preserves safe cancellation and conditional-write semantics.
- Adds resilience, diagnostic, and unit-test coverage.
| File | Summary |
|---|---|
test/Extensions/Orleans.Clustering.ZooKeeper.Tests/ZooKeeperReadRetryTests.cs |
Tests retries, cancellation, fencing, and mutations. |
test/Extensions/Orleans.Clustering.ZooKeeper.Tests/ZooKeeperReadResilienceTests.cs |
Adds functional resilience scenarios. |
test/Extensions/Orleans.Clustering.ZooKeeper.Tests/ZooKeeperNativeDiagnostics.cs |
Captures native diagnostics. |
test/Extensions/Orleans.Clustering.ZooKeeper.Tests/ZooKeeperBasedMembershipTableUnitTests.cs |
Adds membership and diagnostics tests. |
test/Extensions/Orleans.Clustering.ZooKeeper.Tests/Orleans.Clustering.ZooKeeper.Tests.csproj |
Adds test dependencies. |
src/Orleans.Clustering.ZooKeeper/ZooKeeperSession.cs |
Manages native operations and asynchronous close. |
src/Orleans.Clustering.ZooKeeper/ZooKeeperReadRetryPolicy.cs |
Defines connection-loss retry behavior. |
src/Orleans.Clustering.ZooKeeper/ZooKeeperGatewayListProvider.cs |
Applies resilient gateway reads. |
src/Orleans.Clustering.ZooKeeper/ZooKeeperBasedMembershipTable.cs |
Integrates sessions, retries, and fenced reads. |
src/Orleans.Clustering.ZooKeeper/Orleans.Clustering.ZooKeeper.csproj |
Adds the Polly dependency. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Move provider-specific changes and regression diagnostics to dotnet#11338 while retaining shared conformance wiring and the original-scope deletion probe.
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
Serialize global diagnostic logger state, skip unavailable ZooKeeper functional tests, and correct the test-name typo.
Get a fresh assessment by requesting another Copilot review.
Review effort: Lite
Findings: 3
Native validation remains blocked at b865783Exact-head CI run 35529047552 completed with the two ZooKeeper jobs and aggregate CI failing. There were no unrelated failed jobs. This PR remains draft.
The fixed workload result is 3 completed, 3 failed, 6 unstarted. The new immutable primary-exception snapshots identify all three observed failures as full ReadAll:
All three primary exceptions are
Fourth-retry warnings record scheduled retries, not independent failures or exhausted-operation counts. Reset signatures alone do not establish a common transport cause. Artifacts: net8 diagnostics and TRX, net10 diagnostics and TRX. Earlier exact-head results remain part of the record, in completed/failed/unstarted order: The 199 focused unit tests pass on both frameworks. Scoped reviews of the owner fixes and primary-snapshot follow-up found no significant issues; all four published inline review threads have been answered and resolved. Those results do not supersede the failed native gate or constitute human approval. The implementation retains one native-read retry owner, operation/close lifetime, full snapshot fences, and single-attempt conditional writes. No SDK change, retry-budget/workload tuning, unchanged rerun, broader tracker, or merge has been used to turn this gate green. Further implementation is on hold pending a material decision. |
PR feedback follow-upRechecked the live review threads, review bodies, and discussion at The review summary also recommends skipping functional tests when ZooKeeper is unavailable. I am not applying that suggestion: this PR's native validation requires the configured ZooKeeper service and explicit failures for unavailable infrastructure. Adding a skip would weaken the required gate and conflict with the agreed scope. No additional source change or CI rerun is warranted by this feedback. The draft and head remain unchanged. The recorded native validation failure remains a blocker; resolved review threads do not turn that gate green or constitute human approval. |
Move provider-specific changes and regression diagnostics to dotnet#11338 while retaining shared conformance wiring and the original-scope deletion probe.
8dda CI classification and follow-upRun 35635796336 tested The barrier correctly prevented retrying while disconnected, but one reconnect released every failed row at once. Commit Deterministic tests cover concurrent first attempts, maximum recovery concurrency of one, reconnect-before-registration, failure-before-Disconnected, a second disconnect while waiters are queued, canceled-waiter isolation, reconnect timeout preserving native |
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
Timed-out recovery requests bypass retry admission and can recreate a concurrent request storm.
Get a fresh assessment by requesting another Copilot review.
Review effort: Balanced
Findings: 1
Open (1)
Sequential access revisionThe all-row At the user's direction,
Tests prove one row-native request is active at a time, exact member-before-heartbeat ordering, cancellation before the next row, full-pass fence restart, success on the final allowed attempt, exact exhaustion counts, no stale snapshot/deletion, and cleanup stopping before later rows after exhausted contention. The focused suite passes 206/206 on net8 and net10. A scoped review found no significant issues. Historical fully sequential stress completed the fixed 12/12 workload while socket-reset diagnostics remained, supporting lower load as a mitigation rather than an SDK cure. A fresh exact-head native gate is pending. |
Code coverage
Report-only conclusion: current-main baseline stale. The newest successful coverage run tested 5858077, not current main 2dace6e. Coverage combines every CI test matrix job, including providers, CodeGen, .NET 8/10, Linux, Windows, and macOS, using canonical physical source and branch identities. The comparison remains report-only while normal line and branch variance is calibrated. Coverage details |
Sequential native gate is greenRun 35640986948 tested runtime head
Result: 12 completed, 0 failed, 0 unstarted. Sequential access substantially reduced both load and duration:
The diagnostic listener reached its native-event detail cap in some instances (2 net8, 1 net10), but there were no SDK reset-stack captures or read retry warnings in this run. This is a load-shape reliability result, not a claim that the pinned SDK transport defect is cured. The latest |
Move provider-specific changes and regression diagnostics to dotnet#11338 while retaining shared conformance wiring and the original-scope deletion probe.



Problem
ZooKeeper membership reads can fail with
ConnectionLossException. The provider historically starts every row read concurrently, and recent consistency fencing makes a snapshot perform more requests and replay the complete pass when canonical membership changes during the read. Large concurrent snapshots can amplify the pinned SDK's existing transport instability.The SDK's
ZooKeeper.Usingalso retries an entire callback. Replaying a conditional insert or update after a lost acknowledgment can turn a committed transaction into a false conflict.Solution
BadVersioncontention to five total attempts. Exhaustion reports an explicit consistency or contention failure instead of looping indefinitely, returning stale rows, or silently skipping cleanup.ConnectionLossExceptionfailures at the nativeSync,GetChildren, andGetDataboundaries using one Polly owner: four retries with exponential 250/500/1000/2000 ms delays.false.Initialization, heartbeat updates, and recursive deletion retain their existing SDK callback behavior. Mutation payloads, CAS preconditions, public APIs, the ZooKeeper SDK version, and configuration remain unchanged.
This deliberately trades snapshot latency for lower ZooKeeper request concurrency and improved reliability. It mitigates load amplification without claiming that recent consistency changes introduced the underlying SDK socket-reset behavior.
Scope
This PR contains the ZooKeeper-specific resilience work extracted from #11332. Shared membership-provider conformance wiring remains there.
Microsoft Reviewers: Open in CodeFlow