Очереди задач для C# (.NET): от простого к сложному
Современная разработка на C# (.NET) редко обходится без фоновых задач, отложенной обработки и асинхронных операций. Очереди задач (Job Queues / Message Queues) — ключевой паттерн, позволяющий разгрузить основной поток приложения, гарантировать доставку сообщений и масштабировать обработку. В этой статье мы рассмотрим три популярных подхода к реализации очередей в .NET: встроенный System.Threading.Channels, мощный планировщик Hangfire и промышленный брокер сообщений RabbitMQ с клиентом для .NET.
1. System.Threading.Channels — встроенная очередь в .NET
System.Threading.Channels — это легковесная, потокобезопасная очередь, доступная прямо в .NET (начиная с .NET Core 2.1). Она идеальна для сценариев «производитель-потребитель» внутри одного процесса.
Основные возможности:
- Асинхронное чтение и запись (
await writer.WriteAsync(),await reader.ReadAsync()). - Ограниченные и неограниченные каналы (Bounded / Unbounded).
- Поддержка отмены через
CancellationToken. - Пакетное чтение (
ReadAllAsync).
Пример: простая очередь задач
using System.Threading.Channels;
// Создаем канал с буфером на 100 элементов
var channel = Channel.CreateBounded<string>(100);
// Производитель: добавляем задачи
var producer = Task.Run(async () =>
{
for (int i = 0; i < 10; i++)
{
await channel.Writer.WriteAsync($"Задача {i}");
await Task.Delay(100);
}
channel.Writer.Complete(); // сигнал о завершении
});
// Потребитель: обрабатываем задачи
var consumer = Task.Run(async () =>
{
await foreach (var item in channel.Reader.ReadAllAsync())
{
Console.WriteLine($"Обработано: {item}");
}
});
await Task.WhenAll(producer, consumer);
Плюсы: нулевая зависимость, высокая производительность, идеально для in-memory очередей в одном приложении.
Минусы: не подходит для распределенных систем — данные теряются при перезапуске.
2. Hangfire — продвинутый планировщик фоновых задач
Hangfire — это популярная библиотека для .NET, которая не только реализует очередь, но и предоставляет веб-дашборд, персистентность (SQL Server, Redis, PostgreSQL), повторные попытки и CRON-расписания.
Ключевые возможности:
- Fire-and-forget (запуск один раз).
- Отложенные задачи (Delayed).
- Повторяющиеся задачи (Recurring) — замена Windows Task Scheduler.
- Автоматические retry с настраиваемой политикой.
- Встроенный мониторинг (дашборд).
Пример: базовая настройка Hangfire
// Установка: Install-Package Hangfire
using Hangfire;
using Hangfire.SqlServer;
// Конфигурация в Program.cs (.NET 6+)
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddHangfire(config =>
config.UseSqlServerStorage(builder.Configuration.GetConnectionString("HangfireDb")));
builder.Services.AddHangfireServer();
var app = builder.Build();
app.UseHangfireDashboard(); // /hangfire
// Добавление задач
BackgroundJob.Enqueue(() => Console.WriteLine("Fire-and-forget!"));
BackgroundJob.Schedule(() => Console.WriteLine("Через 5 минут"), TimeSpan.FromMinutes(5));
RecurringJob.AddOrUpdate("my-job", () => Console.WriteLine("Каждую минуту"), Cron.Minutely);
app.Run();
Плюсы: богатая функциональность, сохранение состояния между перезапусками, готовый UI.
Минусы: требует базу данных, не подходит для высоконагруженных распределенных систем (заточен под монолит).
3. RabbitMQ + .NET — распределенная очередь сообщений
RabbitMQ — это промышленный брокер сообщений, реализующий протокол AMQP. Для работы с ним из .NET используется клиентская библиотека RabbitMQ.Client. Это выбор для микросервисной архитектуры, где несколько приложений должны обмениваться задачами.
Базовые понятия:
- Producer — отправляет сообщения в exchange.
- Exchange — маршрутизирует сообщения в очереди по routing key.
- Queue — хранит сообщения до обработки.
- Consumer