https://github.com/soenneker/soenneker.utils.backgroundqueue
A high-performance background Task/ValueTask queue
https://github.com/soenneker/soenneker.utils.backgroundqueue
background csharp dotnet queue task valuetask
Last synced: 2 months ago
JSON representation
A high-performance background Task/ValueTask queue
- Host: GitHub
- URL: https://github.com/soenneker/soenneker.utils.backgroundqueue
- Owner: soenneker
- License: mit
- Created: 2023-03-19T22:17:28.000Z (over 3 years ago)
- Default Branch: main
- Last Pushed: 2026-03-31T13:47:12.000Z (3 months ago)
- Last Synced: 2026-03-31T15:32:23.052Z (3 months ago)
- Topics: background, csharp, dotnet, queue, task, valuetask
- Language: C#
- Homepage: https://soenneker.com
- Size: 2.95 MB
- Stars: 10
- Watchers: 4
- Forks: 1
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Contributing: .github/CONTRIBUTING.md
- Funding: .github/FUNDING.yml
- License: LICENSE
- Code of conduct: .github/CODE_OF_CONDUCT.md
- Security: .github/SECURITY.md
Awesome Lists containing this project
- anything_about_game - backgroundqueue
README
[](https://www.nuget.org/packages/Soenneker.Utils.BackgroundQueue/)
[](https://github.com/soenneker/soenneker.utils.backgroundqueue/actions/workflows/publish-package.yml)
[](https://www.nuget.org/packages/Soenneker.Utils.BackgroundQueue/)
[](https://github.com/soenneker/soenneker.utils.backgroundqueue/actions/workflows/codeql.yml)
#  Soenneker.Utils.BackgroundQueue
### 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 `Task` and `ValueTask`
* Configurable queue size
* Tracks running and pending work
* Simple DI registration
* Hosted service for automatic background processing
---
## Installation
```sh
dotnet add package Soenneker.Utils.BackgroundQueue
```
Register the queue:
```csharp
void ConfigureServices(IServiceCollection services)
{
services.AddBackgroundQueueAsSingleton();
}
```
---
## Starting & Stopping
### Start
```csharp
await serviceProvider.WarmupAndStartBackgroundQueue(cancellationToken);
```
Synchronous start:
```csharp
serviceProvider.WarmupAndStartBackgroundQueueSync(cancellationToken);
```
### Stop
```csharp
await serviceProvider.StopBackgroundQueue(cancellationToken);
```
Synchronous stop:
```csharp
serviceProvider.StopBackgroundQueueSync(cancellationToken);
```
---
## Configuration
```json
{
"Background": {
"QueueLength": 5000,
"LockCounts": false,
"Log": false
}
}
```
* `QueueLength` � Maximum number of queued items
* `LockCounts` � Enables thread-safe tracking of running work
* `Log` � Enables debug logging
---
## Using the Queue
Inject `IBackgroundQueue`:
```csharp
IBackgroundQueue _queue;
void MyClass(IBackgroundQueue queue)
{
_queue = queue;
}
```
### Queueing a `ValueTask`
```csharp
await _queue.QueueValueTask(_ => someValueTask(), cancellationToken);
```
### Queueing a `Task`
```csharp
await _queue.QueueTask(_ => someTask(), cancellationToken);
```
---
## ?? 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)
```csharp
await _queue.QueueTask(ct => DoWorkAsync(id, ct));
```
If `id` is a local variable, this creates a closure.
---
## ? Recommended: Pass State Explicitly
Use the stateful overloads with `static` lambdas.
### ValueTask
```csharp
await _queue.QueueValueTask(
myService,
static (svc, ct) => svc.ProcessAsync(ct),
ct);
```
### Task
```csharp
await _queue.QueueTask(
(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
```csharp
await queue.WaitUntilEmpty(cancellationToken);
```
---
## Task Tracking
Check if work is still processing:
```csharp
bool isProcessing = await queueInformationUtil.IsProcessing(cancellationToken);
```
Get current counts:
```csharp
var (taskCount, valueTaskCount) =
await queueInformationUtil.GetCountsOfProcessing(cancellationToken);
```