Фоновые задачи: IHostedService, BackgroundService, Worker, Hangfire и Quartz
↑ 3.5 Инфраструктура приложения: ошибки, health checks, фоновые задачи · ← Предыдущая · → Следующая
Зачем это на собесе
Что использовать для периодических и отложенных задач и как не потерять работу при перезапуске.
Объяснение
public class CleanupWorker(IServiceScopeFactory scopes, ILogger<CleanupWorker> log) : BackgroundService
{
protected override async Task ExecuteAsync(CancellationToken ct)
{
using var timer = new PeriodicTimer(TimeSpan.FromMinutes(5));
while (await timer.WaitForNextTickAsync(ct))
{
try
{
using var scope = scopes.CreateScope();
await scope.ServiceProvider.GetRequiredService<ICleanup>().RunAsync(ct);
}
catch (Exception ex) when (ex is not OperationCanceledException)
{
log.LogError(ex, "Cleanup failed"); // цикл не должен умирать
}
}
}
}
builder.Services.AddHostedService<CleanupWorker>();| Инструмент | Когда |
|---|---|
BackgroundService | простые периодические/длительные процессы, обработка очереди в памяти |
| Worker Service | отдельный процесс без веб-части (консюмеры, обработчики) |
| Hangfire | отложенные/повторяющиеся задачи, ретраи, дашборд, хранение в БД |
| Quartz.NET | сложные расписания (cron), кластеризация |
| Outbox + очередь | надёжная доставка событий и задач |
Нюансы и подводные камни
- Исключение в
ExecuteAsync(.NET 6+) останавливает приложение по умолчанию (BackgroundServiceExceptionBehavior.StopHost) — ловите внутри цикла. - Scoped-зависимости получайте через scope (см. Keyed services, фабрики, декораторы, IServiceScopeFactory).
- В нескольких репликах задача выполнится в каждой: нужны distributed lock или планировщик со standalone-хранилищем.
- Задачи в памяти теряются при перезапуске; критичное — в очередь/БД.
- Уважайте
CancellationTokenдля graceful shutdown.
Практика
- Напишите периодический воркер на
PeriodicTimerс корректной обработкой ошибок. - Подключите Hangfire с PostgreSQL и добавьте recurring job.
- Реализуйте distributed lock на Redis или advisory lock в PostgreSQL.
Вопросы с ответами
Чем IHostedService отличается от BackgroundService?
BackgroundService— базовый класс с готовымExecuteAsyncи управлением жизненным циклом поверхIHostedService.
Как выполнять задачу раз в час в нескольких репликах?
Один планировщик с общим хранилищем (Hangfire/Quartz cluster) или distributed lock.
Hangfire или BackgroundService?
Hangfire — когда нужны персистентность, ретраи и дашборд; BackgroundService — для лёгких задач.