Skip to content

BackgroundService: create task using TaskCreationOptions.LongRunning to prevent thread pool starvation#124608

Closed
srnwmnn wants to merge 5 commits intodotnet:mainfrom
srnwmnn:prevent-thread-pool-starvation-in-background-service
Closed

BackgroundService: create task using TaskCreationOptions.LongRunning to prevent thread pool starvation#124608
srnwmnn wants to merge 5 commits intodotnet:mainfrom
srnwmnn:prevent-thread-pool-starvation-in-background-service

Conversation

@srnwmnn
Copy link

@srnwmnn srnwmnn commented Feb 19, 2026

Summary

This change updates how the background ExecuteAsync method is started within the BackgroundService.

Previously, ExecuteAsync was launched using Task.Run, which schedules work on the thread pool. This PR replaces that with Task.Factory.StartNew using TaskCreationOptions.LongRunning and TaskScheduler.Default.

Rationale

  • Explicit long-running semantics: TaskCreationOptions.LongRunning signals that the operation is expected to be long-lived, allowing the runtime to provision a dedicated thread instead of relying on the shared thread pool.
  • Improved thread pool behavior: Avoids potential thread pool starvation for workloads where ExecuteAsync runs for the lifetime of the service.
  • Preserves existing behavior: Cancellation semantics and lifecycle management remain unchanged; the host still observes and handles the ExecuteAsync task as before.

Impact

  • No functional changes to service startup or shutdown behavior.
  • Improved alignment with best practices for long-running background operations.
  • Reduced risk of thread pool contention under sustained load.

@dotnet-policy-service dotnet-policy-service bot added the community-contribution Indicates that the PR has been added by a community member label Feb 19, 2026
@dotnet-policy-service
Copy link
Contributor

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

@davidfowl
Copy link
Member

What do you think this is actually improving?

@srnwmnn
Copy link
Author

srnwmnn commented Feb 22, 2026

It prevents long-running, blocking I/O operations from occupying ThreadPool worker threads, which could otherwise contribute to ThreadPool starvation under load.

In our specific case, the synchronous Consume method of the Confluent Kafka client performs a blocking call. Running this operation on a ThreadPool worker thread risks exhausting available workers when the system is under pressure, potentially impacting request processing and overall application responsiveness.

@davidfowl
Copy link
Member

I don't think we need all background services to pay that cost of spinning up a new thread just in case the code you are using blocks. If you are using the kafka client that is not async then scope that operation by using a thread with blocking APIs.

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

Labels

area-Extensions-Hosting community-contribution Indicates that the PR has been added by a community member

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants