Запуск фоновой задачи по запросу в asp. net core 3.x - PullRequest
2 голосов
/ 13 июля 2020

Я пытаюсь запустить фоновую задачу по запросу всякий раз, когда я получаю определенный запрос от моей конечной точки api. Все, что нужно сделать, - это отправить электронное письмо с задержкой на 30 секунд. Так что я подумал, что BackgroundService подойдет. Но проблема в том, что, похоже, BackgroundService в основном предназначен для повторяющихся задач, а не для выполнения по запросу в соответствии с этим ответом .

Итак, какие еще альтернативы у меня есть, я надеюсь, что нет полагаться на сторонние библиотеки, такие как Hangfire? Я использую asp. net core 3.1.

Это моя фоновая служба.

using System;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;

namespace ProjectX.Services {
    public  class EmailOfflineService : BackgroundService {

        private readonly ILogger<EmailOfflineService> log;
        private readonly EmailService emailService;
        public EmailOfflineService(
            ILogger<EmailOfflineService> log, 
            EmailService emailService
        ) {
            this.emailService = emailService;
            this.log = log;
        }

        protected async override Task ExecuteAsync(CancellationToken stoppingToken)
        {

            log.LogDebug("Email Offline Service Starting...");
            stoppingToken.Register(() => log.LogDebug("Email Offline Service is stopping."));

            while(!stoppingToken.IsCancellationRequested)
            {
                // wait for 30 seconds before sending
                await Task.Delay(1000 * 30, stoppingToken);

                await emailService.EmailOffline();
                
                // End the background service
                break;
            }
            log.LogDebug("Email Offline Service is stoped.");
        }
    }
}

Ответы [ 3 ]

5 голосов
/ 20 июля 2020

Вы можете попытаться объединить очередь asyn c с BackgroundService.

public class BackgroundEmailService : BackgroundService
{
    private readonly IBackgroundTaskQueue _queue;

    public BackgroundEmailService(IBackgroundTaskQueue queue)
    {
        _queue = queue;
    }

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        while (!stoppingToken.IsCancellationRequested)
        {
            var job = await _queue.DequeueAsync(stoppingToken);
            
            _ = ExecuteJobAsync(job, stoppingToken);
        }
    }

    private async Task ExecuteJobAsync(JobInfo job, CancellationToken stoppingToken)
    {
        try
        {
            await Task.Delay(TimeSpan.FromSeconds(30), stoppingToken);
            // todo send email
        }
        catch (Exception ex)
        {
            // todo log exception
        }
    }
}

public interface IBackgroundTaskQueue
{
    void EnqueueJob(JobInfo job);

    Task<JobInfo> DequeueAsync(CancellationToken cancellationToken);
}

Таким образом, вы можете вставить IBackgroundTaskQueue в свой контроллер и поставить в него задания, в то время как JobInfo будет содержать некоторая базовая c информация для выполнения задания в фоновом режиме, например:

public class JobInfo
{
    public string EmailAddress { get; set; }
    public string Body { get; set; }
}

Пример фоновой очереди (на основе ASP. NET основной документации ):

public class BackgroundTaskQueue : IBackgroundTaskQueue
{
    private ConcurrentQueue<JobInfo> _jobs = new ConcurrentQueue<JobInfo>();
    private SemaphoreSlim _signal = new SemaphoreSlim(0);

    public void EnqueueJob(JobInfo job)
    {
        if (job == null)
        {
            throw new ArgumentNullException(nameof(job));
        }

        _jobs.Enqueue(job);
        _signal.Release();
    }

    public async Task<JobInfo> DequeueAsync(CancellationToken cancellationToken)
    {
        await _signal.WaitAsync(cancellationToken);
        _jobs.TryDequeue(out var job);

        return job;
    }
}
0 голосов
/ 18 июля 2020

Я думаю, что самый простой подход - сделать вызов и забыть в коде обработки запроса на отправку электронной почты, например:

//all done, time to send email
Task.Run(async () => 
{
    await emailService.EmailOffline(emailInfo); //assume all necessary info to send email is saved in emailInfo
});

Это запустит поток для отправки Эл. адрес. Код немедленно вернется к звонящему. В методе EmailOffline вы можете включить логи задержки по времени c по мере необходимости. Не забудьте также включить в него журнал регистрации ошибок c, в противном случае исключения из EmailOffline могут игнорироваться.

0 голосов
/ 16 июля 2020

Используйте Hangfire, его функции фоновых методов великолепны и бесплатно предоставляют вам красивую панель инструментов: https://docs.hangfire.io/en/latest/background-methods/index.html

...