Back to results for “Threading”
.NET › Background Services

What are common patterns for implementing a producer-consumer background processing pipeline using Channel<T> with a BackgroundService?

Advanced

Answer

System.Threading.Channels provides Channel<T>, a high-performance, thread-safe async queue -- a producer (e.g., an API endpoint) writes items via ChannelWriter.WriteAsync, while a BackgroundService acts as the consumer, reading items via ChannelReader.ReadAllAsync in a loop, decoupling request-handling latency from background processing time while providing built-in backpressure if the channel has bounded capacity.
var channel = Channel.CreateBounded<EmailMessage>(capacity: 100);
builder.Services.AddSingleton(channel.Writer);
builder.Services.AddSingleton(channel.Reader);
builder.Services.AddHostedService<EmailSenderService>();

public class EmailSenderService : BackgroundService {
    protected override async Task ExecuteAsync(CancellationToken ct) {
        await foreach (var message in _reader.ReadAllAsync(ct)) {
            await SendEmailAsync(message);
        }
    }
}
Real-world example An API endpoint accepting bulk email requests writes each email to a bounded Channel and returns immediately (202 Accepted), while a background service consumes and actually sends the emails, keeping the API responsive under heavy load.

Common follow-ups: What happens when a bounded channel is full and a producer tries to write?;How does this pattern compare to using an external message queue like RabbitMQ?