Skip to content

Use async ChangeToken.OnChange overload in FileConfigurationProvider#130492

Open
svick wants to merge 1 commit into
dotnet:mainfrom
svick:use-async-changetoken-onchange
Open

Use async ChangeToken.OnChange overload in FileConfigurationProvider#130492
svick wants to merge 1 commit into
dotnet:mainfrom
svick:use-async-changetoken-onchange

Conversation

@svick

@svick svick commented Jul 10, 2026

Copy link
Copy Markdown
Member

Uses the new async (Func<Task>) overload of ChangeToken.OnChange (see #69099) in FileConfigurationProvider.

The reload callback previously blocked a thread for the whole reload delay via Thread.Sleep(Source.ReloadDelay). It now awaits Task.Delay(...) instead, so no thread is blocked while waiting out the debounce delay before reloading:

_changeTokenRegistration = ChangeToken.OnChange(
    () => Source.FileProvider.Watch(Source.Path!),
    async () =>
    {
        await Task.Delay(Source.ReloadDelay).ConfigureAwait(false);
        Load(reload: true);
    });

Why only this call site

The other in-repo callers of ChangeToken.OnChange (ConfigurationRoot, ConfigurationManager, OptionsMonitor) invoke short, synchronous, non-blocking consumers (RaiseChanged / InvokeChanged) and gain nothing from the async overload, so they are intentionally left unchanged.

A closely related change is at dotnet/aspnetcore#67732.

Note

This PR description was generated by GitHub Copilot.

Replace the blocking Thread.Sleep in the reload callback with an
awaited Task.Delay, using the new async Func<Task> overload of
ChangeToken.OnChange (dotnet#69099). This avoids blocking a thread for the
duration of the reload delay.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 059bf1b8-31e2-4608-a038-210880f90d06
@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @dotnet/area-extensions-configuration
See info in area-owners.md if you want to be subscribed.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

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 updates FileConfigurationProvider’s file-change reload callback to use the async ChangeToken.OnChange overload and replace a blocking Thread.Sleep debounce with an awaited Task.Delay, aiming to avoid tying up a thread during the reload delay.

Changes:

  • Replace Thread.Sleep(Source.ReloadDelay) with await Task.Delay(Source.ReloadDelay).ConfigureAwait(false) inside the reload callback.
  • Switch the callback passed to ChangeToken.OnChange to an async lambda (binding to the Func<Task> overload).
  • Update using directives accordingly (System.ThreadingSystem.Threading.Tasks).

Comment on lines 34 to 40
_changeTokenRegistration = ChangeToken.OnChange(
() => Source.FileProvider.Watch(Source.Path!),
() =>
async () =>
{
Thread.Sleep(Source.ReloadDelay);
await Task.Delay(Source.ReloadDelay).ConfigureAwait(false);
Load(reload: true);
});

@svick svick Jul 10, 2026

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

In the synchronous case, the exception is rethrown in whatever the IFileProvider uses for watching. In case it's PhysicalFilesWatcher, the exception is swallowed anyway.

So I don't think this is a problem.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

It holds specifically for PhysicalFilesWatcher (the provider behind  AddJsonFile / AddXmlFile  etc.). A hypothetical custom IFileProvider that invokes token callbacks synchronously and lets exceptions propagate would surface the error in the sync model but not the async one. That is within the async overload's documented contract ("asynchronous exceptions are left unobserved"). I know this is minor issue but is it possible?

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants