Я слишком много исследовал о способах отправки запланированных писем с помощью основного веб-API .NET с использованием фоновых задач. Я знаю, что лучше выполнять фоновые задачи в службе Windows, которая работает отдельно с доменом приложения.
Но мое требование от веб-клиента. У меня будет таблица, в которой каждая строка является рекламным событием для клиента, я могу выбрать активировать, приостановить, остановить для каждого из них, затем он вызовет API и отсюда.
Я должен реализовать каждую фоновую задачу для каждой из них, которая может работать синхронно. Я должен сделать это через Web API, потому что у конечных пользователей нет места для размещения службы.
Фактическое решение :
Через день я пришел к решению, которое использует IHostedService
с BlockingCollection
для управления фоновыми задачами во время выполнения, как показано ниже:
Код для фоновой задачи с использованием IHostedService:
namespace SimCard.API.Worker
{
internal class TimedHostedService : IHostedService, IDisposable
{
private CancellationTokenSource _tokenSource;
private readonly ILogger _logger;
private Timer _timer;
private readonly TasksToRun tasks;
private readonly IEmailService emailService;
public TimedHostedService(ILogger<TimedHostedService> logger, TasksToRun tasks, IEmailService emailService)
{
this.emailService = emailService;
this.tasks = tasks;
_logger = logger;
}
public Task StartAsync(CancellationToken cancellationToken)
{
tasks.Dequeue();
_logger.LogInformation("Timed Background Service is starting.");
_timer = new Timer(DoWork, null, TimeSpan.Zero,
TimeSpan.FromSeconds(5));
return Task.CompletedTask;
}
private void DoWork(object state)
{
emailService.SendEmail("ptkhuong96@gmail.com", "Test", "OK, Done now");
_logger.LogInformation("Mail sent!");
}
public Task StopAsync(CancellationToken cancellationToken)
{
_logger.LogInformation("Timed Background Service is stopping.");
_timer?.Change(Timeout.Infinite, 0);
return Task.CompletedTask;
}
public void Dispose()
{
_timer?.Dispose();
}
}
}
Вот код для BlockingCollection:
namespace SimCard.API.Worker
{
public class TasksToRun : ITasksToRun
{
private readonly BlockingCollection<int> _tasks;
public TasksToRun() => _tasks = new BlockingCollection<int>();
public void Enqueue(int settings) => _tasks.Add(settings);
public void Dequeue() => _tasks.Take();
}
}
И код в контроллере с вызовом из веб-клиента:
[HttpPost("/api/worker/start")]
public IActionResult Run()
{
tasks.Enqueue(15);
return Ok();
}
Код для Startup.cs:
services.AddHostedService<TimedHostedService>();
services.AddSingleton<TasksToRun, TasksToRun>();
Проблема:
- После нажатия активной кнопки для первого события => будет вызван контроллер и будет запущен один экземпляр этой фоновой задачи. Как приостановить эту задачу и возобновить ее?
- Если первая проблема решена, как я могу создать каждую фоновую задачу для каждого события в таблице, подумайте о том, могу ли я создать в будущем все больше и больше событий, как одно событие может быть активировано, остановлено, приостановлено, возобновлено без влияния на другого?
Я действительно застрял с этим требованием и не знаю, как действовать дальше. Если у вас есть другой подход, который может адаптировать мой случай, вы также можете порекомендовать меня.
Большое спасибо за вашу поддержку.