Best Practice LongRunning Task creation
Data Structures & Algorithms practice on Codemia
Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.
Introduction
In .NET, a "long-running task" usually means work that should not compete with short request-handling tasks on the normal thread-pool path. The right design is less about forcing work into a task and more about deciding whether the work is CPU-bound, I/O-bound, recurring, or service-like.
The best practice is to choose a lifetime model first, then pick the task API. In many cases, async methods or hosted services are better than TaskCreationOptions.LongRunning.
Know When LongRunning Is Appropriate
TaskCreationOptions.LongRunning is a hint to the scheduler that the work may deserve its own dedicated thread. That can be useful for a worker loop that runs for a long time and does real synchronous work.
It is not a general performance switch. If the task mostly waits on I/O by using await, asking for LongRunning usually adds complexity without benefit.
This console example shows a dedicated worker that runs until cancellation:
That pattern is reasonable when the loop is intentionally long-lived and does blocking work. It is a poor fit for ordinary request work or short jobs.
Prefer async for I/O-Bound Operations
If the task spends most of its time waiting on a database, HTTP call, file operation, or timer, write it as an async method instead of forcing a dedicated thread.
This version scales better because the thread is returned to the runtime while the operation is awaiting external work. That is the key distinction: asynchronous waiting is not the same thing as a long-running CPU worker.
For Application Services, Prefer a Hosted Worker
Inside ASP.NET Core or a worker service, long-lived background logic usually belongs in BackgroundService instead of an ad hoc fire-and-forget task. A hosted service has explicit startup, shutdown, logging, and dependency injection boundaries.
This gives the runtime a clean way to stop the worker during application shutdown. It also avoids a common anti-pattern where code starts a task and then loses track of it.
Design for Cancellation and Observation
Whatever creation model you choose, treat cancellation and error observation as first-class concerns. Long-running work should have a CancellationToken, and exceptions should be awaited, logged, or otherwise observed.
If the task produces items for later processing, prefer a queue such as Channel rather than spinning up a new long-running task for each unit of work. One controlled worker is easier to reason about than many unmanaged ones.
Common Pitfalls
The most common mistake is using TaskCreationOptions.LongRunning for work that is actually asynchronous and mostly idle. That can waste threads and reduce scalability.
Another problem is creating fire-and-forget tasks inside web requests. If the request ends, the task may outlive the request scope, lose dependencies, or be terminated during app shutdown.
It is also easy to forget cancellation. A worker without a stop path becomes hard to shut down cleanly in tests, containers, and production.
Finally, developers sometimes assume "long-running" means "faster." It does not. It is only a scheduler hint, and the wrong hint can make the system worse.
Summary
- Use
LongRunningonly for truly long-lived synchronous work. - Prefer
asyncmethods for I/O-bound operations. - In application code, hosted services are usually better than raw background tasks.
- Always wire in cancellation and observe exceptions.
- Do not create unmanaged fire-and-forget work unless you also own its lifetime.
Related reading
- best way to clear contents of .NET's StringBuilder
- Best way to find a number in an array that's out of order?
- Best way to Format a Double value to 2 Decimal places
- Best way to get distribute a small lookup file using Distributed Cache
- Best way to negate an instanceof
- best way to query on over 15m rows?
- Best way to reduce sequences in an array of strings
- Best way to retrieve K largest elements from large unsorted arrays?

DSA Fundamentals
Master algorithmic patterns and data structures through hands-on LeetCode-style problems - from arrays and hashing to dynamic programming and advanced graphs.
View the courseTrack what you have practised
A free account saves your progress, solutions and study plan across every problem on Codemia.
Data Structures & Algorithms practice on Codemia
Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.