website under development
back to projects

 

© 2026 Filip Jaruška

view source
Jaruška
cv
projects
blog
cvprojectsblogcontact
back to the blog

Separating the Request Loop: A Worker Queue in a .NET Container

.NETASP.NET CoreDockerBackground Jobs
written 18 October 20262 min read

Separating the Request Loop: A Worker Queue in a .NET Container

This came out of the backend for Web Video Streaming, the practical part of my master's thesis.

The Problem

Two Loops Instead of One

The Queue

csharp
1public sealed class TranscodeQueue
2{
3    private readonly Channel<TranscodeJob> _channel = Channel.CreateBounded<TranscodeJob>(
4        new BoundedChannelOptions(100) { FullMode = BoundedChannelFullMode.Wait });
5
6    public ValueTask EnqueueAsync(TranscodeJob job, CancellationToken ct) =>
7        _channel.Writer.WriteAsync(job, ct);
8
9    public IAsyncEnumerable<TranscodeJob> DequeueAllAsync(CancellationToken ct) =>
10        _channel.Reader.ReadAllAsync(ct);
11}
12

The Worker

csharp
1public sealed class TranscodeWorker(
2    TranscodeQueue queue, IServiceScopeFactory scopes, ILogger<TranscodeWorker> log)
3    : BackgroundService
4{
5    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
6    {
7        await foreach (var job in queue.DequeueAllAsync(stoppingToken))
8        {
9            try
10            {
11                using var scope = scopes.CreateScope();
12                await scope.ServiceProvider.GetRequiredService<ITranscoder>()
13                    .TranscodeAsync(job, stoppingToken);
14            }
15            catch (Exception ex) when (ex is not OperationCanceledException)
16            {
17                log.LogError(ex, "Transcode job {Id} failed", job.Id);
18            }
19        }
20    }
21}
22

Wiring It Up

csharp
1builder.Services.AddSingleton<TranscodeQueue>();
2builder.Services.AddHostedService<TranscodeWorker>();
3
4app.MapPost("/videos", async (TranscodeJob job, TranscodeQueue queue, CancellationToken ct) =>
5{
6    await queue.EnqueueAsync(job, ct);
7    return Results.Accepted();
8});
9

Inside the Container

Trade-offs

Results

end.end.

Separating the Request Loop: A Worker Queue in a .NET Container · 2 min readall posts