Skip to content

config: fix silently dropped triggered config refetch when already in-flight#491

Open
garmr-ulfr wants to merge 1 commit into
mainfrom
config-coalesce-refetch
Open

config: fix silently dropped triggered config refetch when already in-flight#491
garmr-ulfr wants to merge 1 commit into
mainfrom
config-coalesce-refetch

Conversation

@garmr-ulfr
Copy link
Copy Markdown
Collaborator

Summary

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 — so after a login, the user could remain on pre-login config for up to ten minutes.

Replaces the atomic.Bool dedup with a mutex-protected fetching/pending pair. A caller arriving during an in-flight fetch sets pending and returns immediately; the in-flight loop re-runs doFetchConfig once 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.

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.
Copilot AI review requested due to automatic review settings May 22, 2026 03:24
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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/pending mechanism that coalesces concurrent fetchConfig calls 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() call confHandler.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.

@garmr-ulfr garmr-ulfr changed the title config: coalesce concurrent fetchConfig calls config: fix silently dropped triggered config refetch when already in-flight May 22, 2026
@myleshorton
Copy link
Copy Markdown
Contributor

Nice! I think this also means that callbacks associated with that config won't happen right? Which will mess up the bandit.

@garmr-ulfr
Copy link
Copy Markdown
Collaborator Author

I think this also means that callbacks associated with that config won't happen right? Which will mess up the bandit.

That's a good question. Are you referring to the offline URLTests?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants