Зачем нам нужны HostedServices, если у нас есть обычные System.Timers? - PullRequest
0 голосов
/ 08 октября 2019

Я читал документацию и статьи о HostedServices в .NET Core и. Но я не понимаю, как его использовать. Моя задача довольно распространенная. У меня есть метод, который будет отправлять Push-уведомления на мобильный телефон (через Google FCM Messaging) каждые 60 секунд. Итак, я хотел бы:

  • Запустить его с моего контроллера;
  • Остановите его на моем контроллере;
  • Показать на представлении отправка продолжается или нет;
  • Использовать .NET Core DI.

Я покажу вам мой код.

BackgroundService

public class PushingHostedService : BackgroundService
{
    private int _executionCount;
    private readonly ILogger<PushingHostedService> _logger;
    private readonly int _seconds = 1000 * 10; 
    private Timer _timer;

    // repos
    private readonly IPushTemplateRepository _pushTemplateRepository;
    private readonly ICustomerEventRepository _customerEventRepository;
    private readonly IPushRepository _pushRepository;
    private readonly ISenderLogRepository _senderLogRepository;
    public readonly IDistributionRepository _distributionRepository;

    // services
    private readonly IPushTemplateService _pushTemplateService;

    private readonly ISendPushService _sendPushService;

    public PushingHostedService(ILogger<PushingHostedService> logger, IPushTemplateRepository pushTemplateRepository,
        ICustomerEventRepository customerEventRepository, IPushRepository pushRepository,
        ISenderLogRepository senderLogRepository, IPushTemplateService pushTemplateService,
        ISendPushService sendPushService, IDistributionRepository distributionRepository)
    {
        _logger = logger;
        _pushTemplateRepository = pushTemplateRepository;
        _customerEventRepository = customerEventRepository;
        _pushRepository = pushRepository;
        _senderLogRepository = senderLogRepository;
        _pushTemplateService = pushTemplateService;
        _sendPushService = sendPushService;
        _distributionRepository = distributionRepository;

        _executionCount = _senderLogRepository.PushTemplates.Count();
    }

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        _logger.LogDebug($"Sender is started ...");

        stoppingToken.Register(() =>
            _logger.LogDebug($"Sender is stopping ..."));

        while (!stoppingToken.IsCancellationRequested)
        {
            await Send();
            await Task.Delay(_seconds, stoppingToken);
        }

        _logger.LogDebug($"Sender is stopped ...");
    }

    public async Task Send() { ... send push via this method }
}

Controller

public class SenderLogController : Controller
{
    private readonly ISenderLogRepository _senderLogRepository;
    private readonly PushingHostedService _pushingHostedService;

    public SenderLogController(ISenderLogRepository senderLogRepository, PushingHostedService pushingHostedService)
    {
        _senderLogRepository = senderLogRepository;
        _pushingHostedService = pushingHostedService;
    }

    public IActionResult Index(int? pageNumber)
    {
        var page = pageNumber ?? 1;

        var senderLogs = _senderLogRepository.PushTemplates.OrderByDescending(x => x.SenderLogId).ToPagedList(page, 10);

        return View(senderLogs);
    }

    public async Task<IActionResult> StopSender()
    {
        await _pushingHostedService.StopAsync(CancellationToken.None);

        return RedirectToAction("Index");
    }

    public async Task<IActionResult> StartSender()
    {
        await _pushingHostedService.StartAsync(CancellationToken.None);

        return RedirectToAction("Index");
    }

View

<span>
    @if (some thing here ...)
    {
        <strong class="text-success">Pushing is going on!!!</strong>   
    }
    else
    {
        <strong>Pushing is switched off</strong>   
    }
</span>

С помощью моего кода я могузапустить и остановить отправку. Но я могу сделать это только один раз.

Может кто-нибудь дать мне понятный пример, как это реализовать? Спасибо!

Обновление

'Как остановить / запустить / проверить, запущена ли фоновая задача HostedService (.NET Core 2.2)?'- это было название вопроса до обновления. Я решил изменить название после некоторых экспериментов. Я выполнил свою задачу с помощью обычного System.Timers. Я покажу вам код.

Scheduler class

public class Scheduler
{
    private const int MSecond = 1000;
    private readonly int _seconds = MSecond * 10;
    private Timer _aTimer;

    public void Start()
    {
        Console.WriteLine("Sending is started ...");

        _aTimer = new Timer();
        _aTimer.Interval = _seconds;

        _aTimer.Elapsed += OnTimedEvent;

        _aTimer.AutoReset = true;

        _aTimer.Enabled = true;
    }

    public bool IsWorking()
    {
        return _aTimer != null;
    }

    private void OnTimedEvent(object sender, ElapsedEventArgs e)
    {
        Console.WriteLine("Send ...");
    }

    public void Stop()
    {
        _aTimer.Stop();
        _aTimer = null;
    }
}

Controller

public class HomeController : Controller
{
    private readonly Scheduler _scheduler;

    public HomeController(Scheduler scheduler)
    {
        _scheduler = scheduler;
    }

    public IActionResult Index()
    {
        ViewBag.isSendingWorking = _scheduler.IsWorking();

        return View();
    }

    public IActionResult Privacy()
    {
        return View();
    }

    public IActionResult On()
    {
        _scheduler.Start();
        return Redirect(Url.Action("Index"));
    }

    public IActionResult Off()
    {
        _scheduler.Stop();

        return Redirect(Url.Action("Index"));
    }
}

И DI от Startup.cs

services.AddSingleton<Scheduler>();

Работает хорошо! И это решает задачу с запуском некоторого фонового задания. Поэтому я не понимаю, зачем нам HostedServices. Документация говорит мне, что HostedServices предназначен для фоновых задач с таймером тоже. ТАК какую прибыль я могу получить от HostedServices? Или таймер лучше для моего случая? А может кто-нибудь поделиться опытом, как лучше решить эту задачу? Возможно, у меня будет только одна задача, но, может быть, в ближайшем будущем у меня будет больше фоновых задач.

...