Qwen, WorkerServices, DedicatedWorker
https://chat.qwen.ai/s/350fc6ec-dc1b-4fa5-9d49-351c5f52c222?fev=0.2.57
D:\Projects\VS\2605\BackgroundVersusWorker\Qwen\DedicatedWorker\DedicatedWorker.slnx
D:\Projects\VS\2605\BackgroundVersusWorker\Qwen\DedicatedWorker\DedicatedWorker01\DedicatedWorker01.csproj------------------------------------------------------------------------------------ https://chat.qwen.ai/s/350fc6ec-dc1b-4fa5-9d49-351c5f52c222?fev=0.2.57 ------------------------------------------------------------------------------------ DedicatedWorker/ ├── Program.cs ├── Worker.cs # Переименованный/доработанный Worker : BackgroundService ├── WorkerSettings.cs # Настройки из appsettings.json ├── appsettings.json └── DedicatedWorker.csproj ---------------------------------------- WorkerSettings.cs ---------------------------------------- public class WorkerSettings { public int BatchSize { get; set; } = 50; public int ProcessingIntervalSeconds { get; set; } = 10; } ---------------------------------------- appsettings.json ---------------------------------------- { "Logging": { "LogLevel": { "Default": "Information" } }, "WorkerSettings": { "BatchSize": 100, "ProcessingIntervalSeconds": 5 } } ----------------------------------------- Worker.cs ----------------------------------------- public class Worker : BackgroundService { private readonly ILogger<Worker> _logger; private readonly IOptions<WorkerSettings> _settings; public Worker(ILogger<Worker> logger, IOptions<WorkerSettings> settings) { _logger = logger; _settings = settings; } protected override async Task ExecuteAsync(CancellationToken stoppingToken) { _logger.LogInformation("🚀 DedicatedWorker запущен. BatchSize={BatchSize}", _settings.Value.BatchSize); // Цикл обработки с явной обработкой ошибок и перезапуском while (!stoppingToken.IsCancellationRequested) { try { await ProcessDataBatchAsync(_settings.Value.BatchSize, stoppingToken); // Пауза между итерациями await Task.Delay(TimeSpan.FromSeconds(_settings.Value.ProcessingIntervalSeconds), stoppingToken); } catch (OperationCanceledException) { _logger.LogInformation("🛑 Graceful shutdown requested."); break; } catch (Exception ex) { _logger.LogError(ex, "💥 Ошибка обработки батча. Повтор через {Interval}с", _settings.Value.ProcessingIntervalSeconds); // В продакшене сюда часто добавляют экспоненциальную задержку или alert await Task.Delay(TimeSpan.FromSeconds(_settings.Value.ProcessingIntervalSeconds), stoppingToken); } } } private async Task ProcessDataBatchAsync(int batchSize, CancellationToken token) { _logger.LogInformation("📦 Обработка батча размером {Size}...", batchSize); // Симуляция тяжелой работы (запрос к БД, чтение очереди, вычисления) await Task.Delay(300, token); _logger.LogInformation("✅ Батч {Size} успешно обработан", batchSize); } } --------------------------------------- Program.cs --------------------------------------- using DedicatedWorker; using Microsoft.Extensions.Hosting; var builder = Host.CreateApplicationBuilder(args); // Привязываем настройки из appsettings.json builder.Services.Configure<WorkerSettings>(builder.Configuration.GetSection("WorkerSettings")); // Регистрируем единственный хостовый сервис builder.Services.AddHostedService<Worker>(); var host = builder.Build(); await host.RunAsync(); // Блокирует поток, пока не придёт сигнал остановки -------------------------------------------------------------------------------------------------- Особенности Нет 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 --------------------------------------------------------------------- Практические рекомендации --------------------------------------------------------------------- Никогда не используйте 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. Паттерны выше полностью совместимы.
Комментариев нет:
Отправить комментарий