Cancel, Backgroundservice, Project
D:\Projects\VS\2606\Quotes\Giga\QuoteGeneratorWorkerSln\QuoteGeneratorWorkerSln.slnx
D:\Projects\VS\2606\Quotes\Giga\QuoteGeneratorWorkerSln\QuoteGeneratorWorker\QuoteGeneratorWorker.csproj
---------------------------------------------------------------------------
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
try
{
_logger.LogInformation("📈 Генератор котировок запущен.");
while (!stoppingToken.IsCancellationRequested)
{
var quotesBatch = GenerateQuotesBatch();
_logger.LogDebug($"--- Новая порция котировок ({quotesBatch.Count} шт.) ---");
// Параллельная обработка текущей партии котировок
await Parallel.ForEachAsync(
quotesBatch,
new ParallelOptions
{
MaxDegreeOfParallelism = Environment.ProcessorCount,
CancellationToken = stoppingToken
},
async (quote, token) =>
{
await _handler.HandleAsync(quote, token);
});
// Ждем перед генерацией следующей порции
await Task.Delay(TimeSpan.FromSeconds(1), stoppingToken);
}
_logger.LogInformation("🛑 Генератор котировок остановлен.");
}
catch (OperationCanceledException)
{
// Эта секция выполнится, когда сервис остановят
_logger.LogInformation("Фоновая задача была корректно прервана.");
}
finally
{
// Здесь можно освободить ресурсы, если они есть
_logger.LogInformation("Сервис QuoteGeneratorService полностью остановлен.");
}
}
// --- НОВАЯ РЕАЛИЗАЦИЯ СТАРТА ---
public override async Task StartAsync(CancellationToken cancellationToken)
{
_logger.LogInformation("📈 Генератор котировок готовится к запуску...");
// Здесь может быть логика инициализации, например:
// await InitializeDatabaseConnectionAsync(cancellationToken);
_logger.LogInformation("🚀 Инициализация завершена. Запуск основного цикла.");
// Вызываем стандартный старт, который начнет ExecuteAsync
await base.StartAsync(cancellationToken);
}
public override async Task StopAsync(CancellationToken cancellationToken)
{
_logger.LogWarning("⚠️ Получен сигнал об остановке сервиса.");
// Здесь может быть логика очистки, например:
// await SaveFinalStateToDatabaseAsync(cancellationToken);
// CloseFileHandles();
// _logger.LogInformation("🛑 Сервис успешно остановлен.");
// Вызываем стандартную остановку
await base.StopAsync(cancellationToken);
}
четверг, 4 июня 2026 г.
Cancel, Backgroundservice, Project
среда, 3 июня 2026 г.
Worker, Background, Worker
Worker, Background, Worker
1. В чем разница между предлагаемыми .Net Core проектов - BackgroundService - Worker 2. Когда необходимо использовать BackgroundService, а когЗавершено размышление
Важно сразу прояснить терминологию:
BackgroundService и Worker — это не альтернативные типы проектов. Это связанные, но разные уровни абстракции в .NET:Понятие | Что это | Уровень |
|---|---|---|
BackgroundService | Абстрактный базовый класс для реализации фоновых задач | Код/Класс |
Worker Service | Шаблон проекта ( dotnet new worker) с готовой инфраструктурой хоста | Проект/Шаблон |
1. В чём разница?
🔹 BackgroundService
- Реализует интерфейс
IHostedService. - Предоставляет единственный метод
ExecuteAsync(CancellationToken), который вызывается при старте приложения. - Автоматически обрабатывает жизненный цикл, отмену через
CancellationToken, логирование незакрытых исключений. - Не требует ручной реализации
StartAsync/StopAsync. - Может использоваться в любом проекте с
Generic Host: Web API, Blazor Server, Console, Desktop и т.д.
🔹 Worker Service (шаблон проекта)
- Это готовая заготовка, создаваемая через
dotnet new workerили в Visual Studio (Worker Service). - Настраивает
IHost(Generic Host) без HTTP-стека, оптимизированный под долгосрочные фоновые процессы. - По умолчанию содержит класс
Worker : BackgroundServiceи регистрацию черезbuilder.Services.AddHostedService<Worker>(). - Включает встроенную поддержку: конфигурации, логирования, DI, graceful shutdown, запуска как systemd-сервиса или Windows Service.
✅ Проще говоря:
Worker — это проект-обёртка, а BackgroundService — это класс, который вы пишете внутри неё (или внутри любого другого хостового приложения).2. Когда что использовать?
🟢 Выбирайте шаблон Worker Service, когда:
- Приложение должно работать постоянно как отдельный процесс/демон (очереди, планировщики, интеграции, мониторинг, ETL).
- Нет необходимости в HTTP API (или он нужен минимально/в отдельном сервисе).
- Планируется развёртывание как:
systemd-сервиса (Linux)- Windows Service
- Docker-контейнера с
restart: always - Kubernetes
Deployment/CronJob
- Вы хотите изолировать фоновую логику от основного приложения (микросервисная архитектура, независимое масштабирование).
🟡 Используйте BackgroundService внутри других проектов (Web API, MVC, Console), когда:
- Фоновая задача вспомогательная и логически связана с основным приложением:
- Очистка кэша/временных файлов
- Рассылка уведомлений после HTTP-запроса
- Синхронизация данных по расписанию
- Вы не хотите создавать отдельный процесс/проект.
- Нужно делиться DI-контейнером, конфигурацией, БД-контекстом с основным приложением.
- Пример: в
Program.csWeb API регистрируетеbuilder.Services.AddHostedService<CacheCleanupService>().
💡 Практические рекомендации
- Не используйте
Thread.Sleep()внутриBackgroundService. Вместо этого: - Обрабатывайте исключения яв
- но.
BackgroundServiceпо умолчанию останавливает хост при незакрытом исключении вExecuteAsync. Оберните логику вtry/catchили используйтеIHostLifetimeдля настройки поведения. - Если нужен HTTP + фон → создавайте
Web APIпроект и добавляйтеBackgroundServiceчерезAddHostedService<T>(). Не смешивайте шаблоны. - В .NET 8+ шаблон
workerиспользует минимальный API хоста и полностью совместим сIHost,IHostedService,Microsoft.Extensions.*.
📌 Краткое резюме
Ситуация | Что выбрать |
|---|---|
Отдельный фоновый процесс/демон/очередь | Шаблон Worker Service + наследование от BackgroundService |
Вспомогательная задача в существующем Web/Console приложении | BackgroundService внутри текущего проекта + AddHostedService<T>() |
Нужен HTTP API + фоновые задачи | Web API проект + регистрация BackgroundService |
Простая одноразовая задача при старте | IHostedService или BackgroundService с stoppingToken.IsCancellationRequested |
Если уточните вашу задачу (очереди, расписание, интеграция, деплой и т.д.), подскажу конкретную структуру проекта и паттерн реализации.
Напиши два отдельных Приложения для примера с типичным использованием - BAckgroundService - Worker
Завершено размышление
Важно сразу зафиксировать: в .NET нет отдельного класса
Worker. Шаблон проекта Worker Service по умолчанию создаёт класс Worker : BackgroundService. Поэтому разница не в типах классов, а в архитектурном контексте, в котором вы используете BackgroundService.Ниже два полноценных, готовых к запуску примера (.NET 8+), демонстрирующих типичные сценарии.
📦 Пример 1: BackgroundService внутри Web API
Сценарий: API-сервер, которому нужна периодическая фоновая задача (очистка кэша, рассылка уведомлений, синхронизация данных). Задача работает в том же процессе, делит DI, конфигурацию и БД с основным приложением.
Структура проекта
12345
Services/CacheCleanupService.cs
csharp 1234567891011121314151617181920212223242526272829303132333435363738394041424344
Program.cs
csharp 123456789101112
🔑 Особенности
- Работает в том же процессе, что и HTTP-конвейер.
- Доступен тот же
IServiceProvider,IConfiguration, БД-контексты. - При остановке
dotnet run/SIGTERMсначала отключаются новые HTTP-запросы, затем ждёт завершенияstoppingToken, потом процесс выходит.
📦 Пример 2: Отдельный проект Worker Service
Сценарий: Демон/фоновый процесс, который ничего не принимает по HTTP. Потребляет задачи из очереди, обрабатывает файлы, делает тяжелые ETL-расчёты. Развёртывается как
systemd, Windows Service или Docker-контейнер.Создание проекта
bash 12
Структура проекта
123456
WorkerSettings.cs
csharp 12345
appsettings.json
json 1234567
Worker.cs
csharp 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647
Program.cs
csharp 12345678910111213
🔑 Особенности
- Нет HTTP-стека → меньше потребление памяти, быстрее старт.
- Готов к запуску как системный сервис:
- Linux:
systemctl enable --now myworker - Windows:
sc create MyWorker binPath="...\DedicatedWorker.exe" - Docker:
restart: always+ healthcheck
- Linux:
- Идеально для горизонтального масштабирования (K8s
Deployment,StatefulSet,CronJob).
📊 Сводная таблица выбора
Критерий | BackgroundService в Web API | Отдельный Worker Service |
|---|---|---|
Процесс | Один процесс с HTTP-сервером | Отдельный процесс/демон |
DI/Конфигурация | Общая с основным приложением | Изолированная, настраивается отдельно |
Масштабирование | Масштабируется вместе с API | Независимое (можно 10 реплик воркера, 2 реплики API) |
Нагрузочное влияние | Фоновая задача может конкурировать за CPU/RAM с HTTP-запросами | Полная изоляция ресурсов |
Типичные задачи | Очистка сессий, отложенные уведомления, периодическая синхронизация | Обработка RabbitMQ/Kafka, ETL, генерация отчётов, мониторинг |
Деплой | Вместе с API | systemd, Windows Service, K8s Worker, Docker |
💡 Практические рекомендации
- Никогда не используйте
while(true) { Thread.Sleep(); }. ИспользуйтеPeriodicTimerилиTask.Delay(..., token), чтобы корректно реагировать на отмену. - Обработка исключений:
BackgroundServiceпо умолчанию останавливает весь хост при незакрытомExceptionвExecuteAsync. Обёртывайте бизнес-логику вtry/catch, если хотите, чтобы процесс продолжил работу. - Если нужен HTTP + фон → создавайте
webapiпроект и регистрируйтеAddHostedService<T>(). Не смешивайтеdotnet new workerсMapControllers(). - В .NET 9 добавлен
BackgroundService.ExecuteAsyncс поддержкойIAsyncDisposableи улучшенным graceful shutdown. Паттерны выше полностью совместимы.
Если скажете вашу конкретную задачу (очереди, расписание, интеграция с БД, требования к деплою), я дам готовый шаблон с нужными пакетами (
MassTransit, Hangfire, Quartz, Dapper и т.д.) и конфигурацией под вашу инфраструктуру.
Подписаться на:
Сообщения (Atom)