A high-performance background Task / ValueTask queue
Overview
BackgroundQueue provides a fast, controlled way to execute background work in .NET applications.
It prevents overload by queueing and processing work asynchronously with configurable limits and built-in tracking.
Features
- Supports both
TaskandValueTask - Configurable queue size
- Tracks running and pending work
- Simple DI registration
- Hosted service for automatic background processing
Installation
Register the queue:
{
services.AddBackgroundQueueAsSingleton();
}
Starting & Stopping
Start
Synchronous start:
Stop
Synchronous stop:
Configuration
"Background": {
"QueueLength": 5000,
"LockCounts": false,
"Log": false
}
}
QueueLength- Maximum number of queued itemsLockCounts- Enables thread-safe tracking of running workLog- Enables debug logging
Using the Queue
Inject IBackgroundQueue:
void MyClass(IBackgroundQueue queue)
{
_queue = queue;
}
Queueing a ValueTask
Queueing a Task
?? Performance Tip: Prefer Stateful Queueing
Avoid capturing variables in lambdas when queueing work. Captured lambdas allocate and can impact performance under load.
? Avoid (captures state)
If id is a local variable, this creates a closure.
? Recommended: Pass State Explicitly
Use the stateful overloads with static lambdas.
ValueTask
myService,
static (svc, ct) => svc.ProcessAsync(ct),
ct);
Task
(logger, id),
static (s, ct) => s.logger.RunAsync(s.id, ct),
ct);
Why this is better:
- No closure allocations
- Lower GC pressure
- Best performance for high-throughput queues
The non-stateful overloads remain available for convenience, but stateful queueing is recommended for hot paths.
Waiting for the Queue to Empty
Task Tracking
Check if work is still processing:
Get current counts:
await queueInformationUtil.GetCountsOfProcessing(cancellationToken);