SOLR-13136: Create new shards in CONSTRUCTION state so queries don't fail during shard creation - #5017
Open
nick-boss-tech wants to merge 10 commits into
Open
SOLR-13136: Create new shards in CONSTRUCTION state so queries don't fail during shard creation#5017nick-boss-tech wants to merge 10 commits into
nick-boss-tech wants to merge 10 commits into
Conversation
…shard on any create failure
…the expected replicas, always activate the shard, index in the test
If waiting for the new shard's replicas to become active fails, delete the half-created slice and fail the create so it can be retried, mirroring the AddReplica failure path in the same method. Previously the shard was activated anyway in a finally block, exposing a shard whose replicas never became active (and whose buffered updates were never applied) to routing. Adds CreateShardCmdTest, which drives the replica wait into its timeout with mocked cluster collaborators and asserts the slice is deleted rather than activated. The test fails against the previous finally-activate behavior.
nick-boss-tech
force-pushed
the
solr-13136-submit
branch
from
October 4, 2026 05:00
2ad4440 to
1821bbf
Compare
…he buffered-updates failure policy in a test
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.
🤖 AI text below 🤖 (posted on behalf of Nick Shanin)
https://issues.apache.org/jira/browse/SOLR-13136
What happens today
A newly created shard becomes visible for queries before its replicas are ready, so queries routed to it during creation can fail with "no servers hosting shard".
What this change does
CreateShardCmdnow creates the shard in CONSTRUCTION state, waits for its replicas to become ACTIVE, and only then flips the shard to active. If creation fails partway, the partial shard is cleaned up instead of being left behind. The cleanup re-reads the cluster state, so replicas already visible there are deleted along with the slice, instead of being left behind as orphaned cores. The cleanup also runs for more failures than before: on base it ran only when adding replicas failed with anAssignmentException, while now any exception from adding replicas, waiting for them to become active, or applying buffered updates triggers it. The cleanup is best effort: the state it reads is this node's local view, so a replica the Overseer has written but this node has not seen yet is missed, as before;DeleteShardCmdwaits one minute for the replica deletions and then removes the slice regardless; and if the cleanup itself fails, that failure is caught and logged at WARN, the slice stays in CONSTRUCTION, and the caller sees only the original create error. One consequence to be aware of: if a new shard's replicas do not become active before the create's replica wait times out, the create now fails and the half-created shard is deleted, so the create must be retried, where the previous behavior activated the shard anyway even when its replicas were not ready.For the unit test,
ShardResponse.setExceptionis now public, so the test can build a failed response; PR #5002 makes the same visibility edit.Proof
Gate record for this branch at head
e6f3f18929f: tidy clean, Error Prone compile clean,:solr:core:check -x testgreen. The tests below were run with Gradle (:solr:core:test) at that head, and run against base production code as well (verified 2026-10-04).CreateShardConstructionTest.testNewShardStaysConstructionUntilReplicasActive(1/1) watches the collection state while a shard is being created and queries throughout, asserting the shard stays in CONSTRUCTION until its replicas are ACTIVE and that no query fails with "no servers hosting shard". On base it fails because base marks the shard ACTIVE as soon as its replicas are added, before they are ACTIVE.CreateShardCmdTest.testReplicaWaitFailureDeletesShardInsteadOfActivatingdrives the replica wait into its timeout and asserts the slice is deleted rather than activated. On base it fails because base has no such wait and activates the shard anyway; the only cleanup on base ran on anAssignmentExceptionfrom adding replicas, with the cluster state snapshot taken before they were added, which lists no replicas to delete. This case also fails against this PR's own previous activate-in-finally behavior, which is how the reversal described below was pinned down.CreateShardCmdTest.testAddReplicaFailureDeletesShardAndReplica(the class is 3/3 at this head) drives the first cleanup block, the one around adding replicas: the replica is registered in the cluster state, creating its core then fails, and the test asserts the cleanup deletes that replica and the slice, never activates the shard, and that the caller sees the original add failure. On base it fails at the replica assertion: base caught only anAssignmentExceptionfrom adding replicas, this failure is not one, and the updates offered on base stop at the createshard and the addreplica, with nothing deleted.CreateShardCmdTest.testBufferedUpdatesFailureDoesNotFailCreatepins the buffered-updates policy described below. Its failure on base is vacuous: base never sendsREQUESTAPPLYUPDATES, so the failure the test answers never occurs there, and that base result says nothing about the policy.A choice to check
This PR takes the position that a shard whose replicas do not become active before the create's wait times out should not be activated. The new slice is deleted and the create fails, so it can be retried.
What that looks like in production: the slice being deleted was created by this same call, sat in CONSTRUCTION state the whole time, and never served a query; its cores hold at most an in-progress copy, and the collection's existing shards are untouched. A guard on whether the slice already existed means a pre-existing shard can never be deleted by this path. Deleting a half-created slice on failure is also what this command already did when adding a replica failed; this change extends that pattern to the wait that follows. The old behavior instead reported success and activated the shard with its replicas not ready, after which queries routed to it failed or returned partial results, and the broken state stayed until an operator cleaned it up by hand.
The cost of the new behavior: on a slow but healthy cluster, a create that would eventually have succeeded can time out, fail, and need a retry, where before it limped in degraded. The alternative is to activate the shard anyway so it is not left unusable in CONSTRUCTION; an earlier version of this PR implemented exactly that, and this version reverses the decision. In outcome the alternative lands close to where the old code ended up, an active shard whose replicas are not ready, though the old code had no construction state and no wait in this flow at all. Was deleting and failing the right call?
Open policy question, flagged for reviewers
Before activation,
CreateShardCmdasks the new shard's leader to apply any updates buffered during construction (REQUESTAPPLYUPDATES). The core refuses that request when it is not buffering, which is expected and harmless. Today the code logs any failure of that step and continues to activation: it does not distinguish the expected not-buffering refusal from a genuine apply failure, and activation proceeds either way. The alternative is to treat a non-refusal failure like the other readiness failures in this flow and abort creation, deleting the new shard. The current code keeps the log-and-continue behavior; flagging it here so reviewers can say whether the stricter policy is wanted.The current policy is pinned by
CreateShardCmdTest.testBufferedUpdatesFailureDoesNotFailCreate, named in Proof above. One limit of that test: it answers the request with a stand-in refusal message ("Core is not buffering updates"), while the real refusal fromRequestApplyUpdatesOpis "Core not in buffering state". Nothing reads the message today, but the stricter policy would have to tell the expected refusal from a genuine failure by that text.Limits
Changelog:
changelog/unreleased/SOLR-13136.yml(type fixed).AI assistance
AI agents assisted with research, implementation, review, and drafting. Nick Shanin directed the work and takes responsibility for this contribution.