config: fix silently dropped triggered config refetch when already in-flight#491
Open
garmr-ulfr wants to merge 1 commit into
Open
config: fix silently dropped triggered config refetch when already in-flight#491garmr-ulfr wants to merge 1 commit into
garmr-ulfr wants to merge 1 commit into
Conversation
A UserChangeEvent firing while a poll-driven fetch was in flight could race the atomic dedup guard, be silently skipped, and leave the handler on stale config until the next ~10-minute poll tick. Replace the guard with a mutex-protected fetching/pending pair: a caller arriving during an in-flight fetch sets pending; the in-flight loop re-runs once after doFetchConfig returns so identity refreshed mid-fetch reliably produces a fresh fetch.
Contributor
There was a problem hiding this comment.
Pull request overview
This PR fixes a race where a UserChangeEvent-triggered config refresh could be skipped while a poll-driven fetch was already in-flight, leaving the app on stale config until the next poll tick.
Changes:
- Replace the atomic “in-flight” guard with a mutex-protected
fetching/pendingmechanism that coalesces concurrentfetchConfigcalls into (at most) a follow-up fetch after the current one completes. - Refactor the existing fetch logic into
doFetchConfig()to support the coalescing loop cleanly. - Add a concurrency regression test and make
LocalBackend.Start()callconfHandler.Start()synchronously.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
| config/config.go | Adds mutex-guarded coalescing to prevent missed refreshes during in-flight fetches; factors fetch body into doFetchConfig(). |
| config/config_test.go | Adds a blocking fetcher + test to verify concurrent calls schedule exactly one coalesced follow-up fetch. |
| backend/radiance.go | Ensures confHandler.Start() runs deterministically during backend startup (no goroutine wrapper). |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Contributor
|
Nice! I think this also means that callbacks associated with that config won't happen right? Which will mess up the bandit. |
myleshorton
approved these changes
May 22, 2026
WendelHime
approved these changes
May 22, 2026
Collaborator
Author
That's a good question. Are you referring to the offline URLTests? |
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.
Summary
A
UserChangeEventfiring while a poll-driven fetch was in flight could race the atomic dedup guard, be silently skipped, and leave the handler on stale config until the next ~10-minute poll tick — so after a login, the user could remain on pre-login config for up to ten minutes.Replaces the
atomic.Booldedup with a mutex-protectedfetching/pendingpair. A caller arriving during an in-flight fetch setspendingand returns immediately; the in-flight loop re-runsdoFetchConfigonce after the current one returns, picking up the freshest identity for the second request. Worst case after an event storm: one extra HTTP round-trip on the stale-identity fetch, then a fresh one.