Skip to content

Conversation

Copilot
Copy link
Contributor

@Copilot Copilot AI commented Oct 13, 2025

Fixes #495675

This PR documents a breaking behavioral change in .NET 10 where BackgroundService.ExecuteAsync now runs entirely on a background thread instead of running the synchronous portion (before the first await) on the main thread during service startup.

What Changed

Previously, the synchronous portion of ExecuteAsync would run on the main thread and block other services from starting. Only code after the first await would run on a background thread. This behavior was intended to allow developers to partition synchronous and asynchronous work, but most implementers didn't understand or expect this nuance.

Starting in .NET 10 Preview 1, all of ExecuteAsync runs on a background thread, and no part of it blocks other services from starting.

Documentation Added

  • Breaking change document: docs/core/compatibility/extensions/10.0/backgroundservice-executeasync-task.md
    • Explains the previous and new behavior with code examples
    • Provides four recommended approaches for developers who need the old behavior:
      1. Place startup code in the constructor
      2. Override StartAsync and call base.StartAsync()
      3. Implement IHostedLifecycleService for more specific startup timing
      4. Implement IHostedService directly instead of using BackgroundService
  • TOC update: Added entry to docs/core/compatibility/toc.yml
  • Index update: Added entry to docs/core/compatibility/10.0.md

References

Original prompt

This section details on the original issue you should resolve

<issue_title>[Breaking change]: BackgroundService runs all of ExecuteAsync as a Task</issue_title>
<issue_description>### Description

See dotnet/runtime#36063
dotnet/runtime#116283, dotnet/runtime#116181

BackgroundService will now run all of ExecuteAsync on a background thread.

We previously would run the synchronous portion of ExecuteAsync on the main thread during service startup, blocking other services from starting, and only things after the first await would run on a background thread.

This was meant to give the implementers of BackgroundService the ability to partition some synchronous work before the first await and async work after.

What we found was that most implementers of BackgroundService did not understand or expect this nuance. To avoid this common pitfall we've moved the entirety of ExecuteAsync to the background.

Version

.NET 10

Previous behavior

The synchronous portion of ExecuteAsync would run on the main thread and block other services from starting.

New behavior

All of ExecuteAsync now runs on a background thread.

Type of breaking change

  • Binary incompatible: Existing binaries might encounter a breaking change in behavior, such as failure to load or execute, and if so, require recompilation.
  • Source incompatible: When recompiled using the new SDK or component or to target the new runtime, existing source code might require source changes to compile successfully.
  • Behavioral change: Existing binaries might behave differently at run time.

Reason for change

Common pitfall, did not meet user's expectations.

Recommended action

If you require any part of your BackgroundService.ExecuteAsync to run earlier, you can do any one of the following:

  1. Place that in the constructor and it will execute as part of the service construction.
  2. Override StartAsync and do some work before calling base.StartAsync. StartAsync retains the behavior that it's synchronous portion will run synchronously during startup and block other services from starting.
  3. Implement IHostedLifecycleService on your BackgroundService if you wish to run something at a more specific time during service startup.
  4. Forgo BackgroundService entirely and implement your own IHostedService

Feature area

Extensions

Affected APIs

Microsoft.Extensions.Hosting


Associated WorkItem - 495675</issue_description>

Comments on the Issue (you are @copilot in this section)

Fixes #48878


✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.


Internal previews

📄 File 🔗 Preview link
docs/core/compatibility/10.0.md Breaking changes in .NET 10
docs/core/compatibility/extensions/10.0/backgroundservice-executeasync-task.md BackgroundService runs all of ExecuteAsync as a Task
docs/core/compatibility/toc.yml docs/core/compatibility/toc

Co-authored-by: gewarren <24882762+gewarren@users.noreply.github.com>
@Copilot Copilot AI changed the title [WIP] Update BackgroundService to run ExecuteAsync on background thread Document breaking change for BackgroundService ExecuteAsync behavior in .NET 10 Oct 13, 2025
@Copilot Copilot AI requested a review from gewarren October 13, 2025 19:56
Copilot finished work on behalf of gewarren October 13, 2025 19:56
@gewarren gewarren marked this pull request as ready for review October 14, 2025 00:28
@gewarren gewarren requested a review from a team as a code owner October 14, 2025 00:28
@gewarren gewarren requested review from Copilot and removed request for a team October 14, 2025 00:28
Copy link
Contributor

@Copilot 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 documents a breaking behavioral change in .NET 10 where BackgroundService.ExecuteAsync now runs entirely on a background thread instead of having its synchronous portion (before the first await) run on the main thread during service startup. The change was made because the previous behavior was a common pitfall that didn't meet user expectations.

Key changes:

  • Added comprehensive breaking change documentation with code examples and migration guidance
  • Updated table of contents and index files to include the new documentation
  • Provided four specific approaches for developers who need the previous synchronous startup behavior

Reviewed Changes

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

File Description
docs/core/compatibility/extensions/10.0/backgroundservice-executeasync-task.md New breaking change document explaining the behavior change and migration options
docs/core/compatibility/toc.yml Added TOC entry for the new breaking change document
docs/core/compatibility/10.0.md Added index entry for the breaking change in the Extensions section

@gewarren gewarren requested review from a team and ericstj October 14, 2025 01:50
Copy link
Member

@BillWagner BillWagner left a comment

Choose a reason for hiding this comment

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

This LGTM.

Let's :shipit:

@gewarren gewarren merged commit 7957045 into main Oct 14, 2025
10 checks passed
@gewarren gewarren deleted the copilot/update-backgroundservice-executeasync branch October 14, 2025 15:47
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.

[Breaking change]: BackgroundService runs all of ExecuteAsync as a Task

3 participants