This came out of the backend for Web Video Streaming, the practical part of my master's thesis.
csharp1public 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
csharp1public 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
csharp1builder.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