Repository navigation
fix: ask the leaders and retry at least once a second when the shard assignments stop coming - #495
Open
codelipenghui wants to merge 3 commits into
Open
codelipenghui wants to merge 3 commits into
codelipenghui wants to merge 3 commits into
Conversation
…assignments stop coming The client asks the service address for the shard assignments, and asks the same address again when the stream breaks, with a wait that grows to a minute (30 s in the retry of the connection). After the failure of a server the coordinator elects the new leaders within seconds, but a service that still routes to the dead server, or to one that lost the coordinator and refuses the clients, kept the client without the assignments, and the wait before its next attempt had grown beyond the election. Ask the servers that the last assignments named as leaders, in turn, once the service address has failed, and go back to the service address when an attempt receives assignments. Cap the wait between the attempts at 1 s, jitter included, in the stream restart and in the retry of the connection. This is the same change as oxia-db/oxia#1892 for the Go client. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: Penghui Li <codelipenghui@gmail.com>
codelipenghui
requested review from
mattisonchao and
merlimat
as code owners
November 10, 2026 19:45
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
The retries of the shard assignments cap the connection backoff at 1 s,
and passed min(minimum, 1 s) as the first delay of the backoff. With a
minimum of 1 s or more both delays were 1 s, which Failsafe rejects
("delay must be < the maxDelay"): asyncClient() threw, and a standalone
client leaked the threads it had started.
When the minimum is not below the cap, wait the cap before each retry.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Penghui Li <penghui@apache.org>
…imum below 1 s The retry of the shard assignments takes the smaller of the connection backoff maximum and 1 s as its maximum, and no test configured a maximum below 1 s. With a backoff of 100 ms to 300 ms, the waits from the third attempt to the seventh take 1.2 s, and 3.2 s if the retry used the 1 s cap instead. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Penghui Li <penghui@apache.org>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Motivation
The client asks the service address for the shard assignments, and asks the same address again when the stream breaks, with a wait that grows to a minute (30 s in the retry of the connection). After the failure of a server the coordinator elects the new leaders within seconds, but a service that still routes to the dead server, or to one that lost the coordinator and refuses the clients, kept the client without the assignments. The wait before its next attempt had grown beyond the election, so the client learned the new leaders late and its operations ran into their deadline. The Go client had the same problem and was fixed in oxia-db/oxia#1892.
Found by chaos testing of the Go client. The Java client was not run through the chaos harness: this change comes from reading its code, which has the same two properties (always the service address, and the 60 s and 30 s maximum waits).
Modifications
RpcProvider.getShardAssignmentstakes aSupplier<String> target, asked for each attempt (nullis the service address). The 2-argument version is replaced.ShardManagerkeeps the leaders of the last assignments. Once the service address has failed, each attempt asks the next of them in turn, and an attempt that receives assignments sends the next one back to the service address.ShardManagerand in the retry of the connection inGrpcRpcProvider.Backoffnever returns more than its maximum. When the minimum of the connection backoff is 1 s or more, the retry of the connection inGrpcRpcProviderwaits 1 s each time: a Failsafe backoff needs its first delay below its maximum.Shared state
ShardManager.serversis an immutable list that the shard manager replaces when the assignments change (volatile) and the attempts read.attemptis anAtomicInteger, reset when assignments arrive.Testing
ShardManagerTest.asksTheLeadersWhenTheServiceAddressFails: the targets are the service address, the service address, each leader, and the service address again after assignments arrived. Fails if the target is always the service address, and if the attempts are not reset.ShardManagerTest.retriesTheAssignmentsAtLeastOncePerSecond: 8 failing attempts finish within 8 s (about 4.5 s with the cap, 12.7 s without it).GrpcRpcProviderTest.getShardAssignmentsAsksTheAddressOfTheTargetandgetShardAssignmentsRetriesAtLeastOncePerSecond, andBackoffTest.neverWaitsLongerThanTheMaximumIncludingTheJitter.GrpcRpcProviderTest.getShardAssignmentsRetriesOncePerSecondWhenTheMinimumIsNotBelowItandConnectionBackoffStartTest(a standalone client, and a client of aSharedResourcespool), each with a connection backoff of (1 s, 30 s) and (2 s, 60 s): the client starts, and the retries of the assignments wait 1 s (two failed attempts, then the third receives them: each case takes about 2.1 s). Without the second commit they fail with Failsafe'sIllegalArgumentException: delay must be < the maxDelay.GrpcRpcProviderTest.getShardAssignmentsKeepsAConnectionBackoffMaximumBelowOneSecond: with a connection backoff of (100 ms, 300 ms), the waits from the third attempt to the seventh take under 2 s (about 1.2 s; 3.2 s when the retry takes the 1 s cap instead of that maximum, which was tried). The first attempt is left out because it also opens the connection, which took 0.4 to 0.65 s here.*ITtests fail to initialize here (Testcontainers finds no Docker); they were not run../gradlew checkas a whole (because of those tests) and a cluster test with the Java client.AI Usage
Claude Code wrote the change, the tests and this description, and ran the tests locally. The contributor asked for it and for the PR to be opened ready for review; this description makes no claim about their review.
🤖 Generated with Claude Code