Skip to content

Make BackgroundService run ExecuteAsync as task - #116283

Merged
ericstj merged 8 commits into
dotnet:mainfrom
ericstj:backgroundServiceFullStartAsync
Jun 11, 2025
Merged

Make BackgroundService run ExecuteAsync as task#116283
ericstj merged 8 commits into
dotnet:mainfrom
ericstj:backgroundServiceFullStartAsync

Conversation

@ericstj

Copy link
Copy Markdown
Member

Fixes#36063

That issue requested that we move the entire BackgroundService.ExecuteAsync to the async part of the method rather than give the service a chance to do synchronous work before it's first await. In this way BackgroundServices will not hold up the start of the application and folks are free to implement ExecuteAsync as a completely blocking method.

This is a breaking change, but one that was deemed acceptable.

CopilotAI review requested due to automatic review settings June 3, 2025 23:13
@ericstjericstj added the breaking-change Issue or PR that represents a breaking API or functional change over a previous release. label Jun 3, 2025
@dotnet-policy-servicedotnet-policy-serviceBot added the needs-breaking-change-doc-created Breaking changes need an issue opened with https://github.com/dotnet/docs/issues/new?template=dotnet label Jun 3, 2025
@ericstj
ericstjforce-pushed the backgroundServiceFullStartAsync branch from 8cea933 to 3e545d3CompareJune 3, 2025 23:14

CopilotAI 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 ensures that all of BackgroundService.ExecuteAsync runs on a background thread to avoid blocking startup, and updates tests to validate the new asynchronous behavior, including support for fully synchronous ExecuteAsync implementations.

  • Wraps ExecuteAsync in Task.Run within StartAsync to push all execution off the caller thread.
  • Updates existing tests to expect TaskCanceledException on immediate cancellation and renames/refactors them.
  • Adds new tests covering synchronous ExecuteAsync implementations and their cancellation/stop behavior.

Reviewed Changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

FileDescription
src/libraries/Microsoft.Extensions.Hosting.Abstractions/src/BackgroundService.csWraps ExecuteAsync call in Task.Run, capturing the returned task.
src/libraries/Microsoft.Extensions.Hosting/tests/UnitTests/BackgroundServiceTests.csRenames/refactors tests and adds new tests for sync execution and stop.

@WeihanLi

Copy link
Copy Markdown
Contributor

Should we expose a config workaround for this breaking change

@ericstj

Copy link
Copy Markdown
MemberAuthor

Should we expose a config workaround for this breaking change

That was specifically covered in #36063 and the API proposal around it. The API to control this was rejected and as a rule we don't proactively add AppContext compat switches until we have a strong signal that we need them. The belief here is that most folks will prefer that their BackgroundTask has the entirety of its ExecuteAsync method run on the background thread. Folks already have the workaround to override StartAsync and do some work before calling base.StartAsync, implement IHostedLifecycleService on their BackGroundService, or forgo BackgroundService and implement their own IHostedService

@WeihanLi

This comment was marked as outdated.

ericstj added 3 commits June 6, 2025 10:45
It's possible the ExecuteAsync task completes in the time between it was
started and StartAsync returns. If so, we were returning it's task.
This leads to non-deterministic error behavior of the StartAsync API as
well as inconsistently honoring `BackgroundServiceExceptionBehavior`
based on this race.
Instead always return a completed task.
…ckgroundService.cs
Co-authored-by: Stephen Toub <stoub@microsoft.com>
@lonix1

Copy link
Copy Markdown

Thank you for finally addressing this! I assume it will be part of v10 to be released in November.

Given the number of years this was open, the large number of people involved, and the potentially breaking or complex changes required on working systems, please reopen the original issue. It was closed by a bot.

There will probably be a need by some to discuss it after upgrading, and it will be very hard to find the correct place; it took me a long time to find that thread and understand the context and underlying issue. You will have many new threads and confusion because of it. Just keep the original one open, please.

@github-actionsgithub-actionsBot locked and limited conversation to collaborators Jul 14, 2025
@ericstjericstj removed the needs-breaking-change-doc-created Breaking changes need an issue opened with https://github.com/dotnet/docs/issues/new?template=dotnet label Oct 2, 2025
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

area-Extensions-Hostingbreaking-changeIssue or PR that represents a breaking API or functional change over a previous release.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Make BackgroundService startup not block host startup

5 participants

@ericstj@WeihanLi@lonix1@stephentoub