четверг, 4 июня 2026 г.

Cancel, Backgroundservice, Project

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);
}

среда, 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.cs Web API регистрируете builder.Services.AddHostedService<CacheCleanupService>().

💡 Практические рекомендации

  1. Не используйте Thread.Sleep() внутри BackgroundService. Вместо этого:
  2. Обрабатывайте исключения яв
  3. но
    . BackgroundService по умолчанию останавливает хост при незакрытом исключении в ExecuteAsync. Оберните логику в try/catch или используйте IHostLifetime для настройки поведения.
  4. Если нужен HTTP + фон → создавайте Web API проект и добавляйте BackgroundService через AddHostedService<T>(). Не смешивайте шаблоны.
  5. В .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, конфигурацию и БД с основным приложением.

Структура проекта

Services/CacheCleanupService.cs

csharp

Program.cs

csharp

🔑 Особенности

  • Работает в том же процессе, что и HTTP-конвейер.
  • Доступен тот же IServiceProvider, IConfiguration, БД-контексты.
  • При остановке dotnet run / SIGTERM сначала отключаются новые HTTP-запросы, затем ждёт завершения stoppingToken, потом процесс выходит.

📦 Пример 2: Отдельный проект Worker Service

Сценарий: Демон/фоновый процесс, который ничего не принимает по HTTP. Потребляет задачи из очереди, обрабатывает файлы, делает тяжелые ETL-расчёты. Развёртывается как systemd, Windows Service или Docker-контейнер.

Создание проекта

bash

Структура проекта

WorkerSettings.cs

csharp

appsettings.json

json

Worker.cs

csharp

Program.cs

csharp

🔑 Особенности

  • Нет HTTP-стека → меньше потребление памяти, быстрее старт.
  • Готов к запуску как системный сервис:
    • Linux: systemctl enable --now myworker
    • Windows: sc create MyWorker binPath="...\DedicatedWorker.exe"
    • Docker: restart: always + healthcheck
  • Идеально для горизонтального масштабирования (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

💡 Практические рекомендации

  1. Никогда не используйте while(true) { Thread.Sleep(); }. Используйте PeriodicTimer или Task.Delay(..., token), чтобы корректно реагировать на отмену.
  2. Обработка исключений: BackgroundService по умолчанию останавливает весь хост при незакрытом Exception в ExecuteAsync. Обёртывайте бизнес-логику в try/catch, если хотите, чтобы процесс продолжил работу.
  3. Если нужен HTTP + фон → создавайте webapi проект и регистрируйте AddHostedService<T>(). Не смешивайте dotnet new worker с MapControllers().
  4. В .NET 9 добавлен BackgroundService.ExecuteAsync с поддержкой IAsyncDisposable и улучшенным graceful shutdown. Паттерны выше полностью совместимы.
Если скажете вашу конкретную задачу (очереди, расписание, интеграция с БД, требования к деплою), я дам готовый шаблон с нужными пакетами (MassTransit, Hangfire, Quartz, Dapper и т.д.) и конфигурацией под вашу инфраструктуру.