fix(api-gateway): populate route WatchSet before watching - #23857
Open
ian-dirac wants to merge 3 commits into
Open
fix(api-gateway): populate route WatchSet before watching#23857ian-dirac wants to merge 3 commits into
ian-dirac wants to merge 3 commits into
Conversation
|
Thank you for your submission! We require that all contributors sign our Contributor License Agreement ("CLA") before we can accept the contribution. Read and sign the agreement Learn more about why HashiCorp requires a CLA and what the CLA includes Have you signed the CLA already but the status is still pending? Recheck it. |
ian-dirac
marked this pull request as ready for review
August 25, 2026 13:28
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.
Description
Problem. API gateway route reconciliation can crash a Consul server with
concurrent map iteration and map writewhen a route references multiple backend services.Root cause. After reading the first backend discovery chain, reconciliation passes
ws.WatchCtxto the asynchronous controller. The route loop then continues populating the samememdb.WatchSetfor later backends whileWatchCtxmay already be iterating the WatchSet's underlying map.Fix. Read and validate every backend discovery chain before registering the trigger. Once
WatchCtxis handed to the controller, reconciliation no longer mutates its WatchSet. If state changes between a discovery-chain read and trigger registration, the existing watch channel is already closed, so the newly registered trigger returns immediately and enqueues another reconciliation.The shared reconciliation path covers HTTP and TCP API gateway routes. This does not change any public API, configuration schema, route matching, or request-routing behavior.
Testing & Reproduction steps
Runtime reproduction shape: configure an API gateway route with at least two distinct backend service names, then update the route or related discovery-chain config entries to cause repeated reconciliation. The affected ordering is:
The last step can mutate the WatchSet while the controller goroutine is iterating it. The panic is scheduler-dependent; #23522 includes reduced HCL and the full source trace.
Deterministic regression coverage:
TestAPIGatewayControllerPopulatesWatchSetBeforeRegisteringTriggerrequires both backend discovery chains to finish processing beforeAddTrigger. Against the previous ordering it fails at trigger registration (want 2,got 0); it passes with this change.TestDiscoveryChainControllernow verifies the missed-update edge case: a discovery-chain change made after the state read but beforeAddTriggercloses the existing watch channel, and registering that WatchSet immediately enqueues reconciliation.Validation run:
gofmt -sandgoimports -local github.com/hashicorp/consul/golangci-lint v2.11.4withhashicorpmetrics(repository-wide on amd64; changed packages on 386)CGO_ENABLED=0 go build -tags=hashicorpmetrics -o /dev/null .go test -tags=hashicorpmetrics ./agent/consul/gateways ./agent/consul/controllerCGO_ENABLED=1 go test -tags=hashicorpmetrics -race -gcflags=all=-d=checkptr=0 ./agent/consul/gateways ./agent/consul/controllerGOARCH=386 CGO_ENABLED=0 go test -tags=hashicorpmetrics ./agent/consul/gateways ./agent/consul/controllerLinks
Fixes #23522
PR Checklist
PCI review checklist
I have documented a clear reason for, and description of, the change I am making.
If applicable, I've documented a plan to revert these changes if they require more than reverting the pull request.
If applicable, I've documented the impact of any changes to security controls.