Фоновые задачи .Net Core Queue - PullRequest
0 голосов
/ 30 июня 2018

Слендер ответил на мой первоначальный вопрос о том, что происходит при запуске и забыл после отправки HTTP-ответа, но теперь у меня остался вопрос, как правильно ставить в очередь фоновые задачи

EDIT

Поскольку все мы знаем, что Async void, как правило, плох, , за исключением случая, когда дело доходит до обработчиков событий , я хотел бы выполнить некоторую фоновую логику без необходимости ожидания клиента. Моей первоначальной идеей было использовать Fire and Forget

Скажите, у меня есть событие:

public event EventHandler LongRunningTask;

А потом кто-то подписывается на пожар и забывает задание:

LongRunningTask += async(s, e) => { await LongNetworkOperation;};

метод веб-API - это вызов:

[HttpGet]
public async IActionResult GetTask()
{
    LongRunningTask?.Invoke(this, EventArgs.Empty);
    return Ok();
}

Но если я сделаю это, моя долгосрочная задача не гарантированно завершится, как я могу справиться с выполнением фоновой задачи, не влияя на время, необходимое для выполнения моего запроса (например, я не хочу ждать задачи закончить первым)?

1 Ответ

0 голосов
/ 01 июля 2018

.Net Core 2.1 имеет IHostedService, который будет безопасно запускать задачи в фоновом режиме. Я нашел пример в Документации для QueuedHostedService, который я изменил, чтобы использовать BackgroundService.

public class QueuedHostedService : BackgroundService
{

    private Task _backgroundTask;
    private readonly ILogger _logger;

    public QueuedHostedService(IBackgroundTaskQueue taskQueue, ILoggerFactory loggerFactory)
    {
        TaskQueue = taskQueue;
        _logger = loggerFactory.CreateLogger<QueuedHostedService>();
    }

    public IBackgroundTaskQueue TaskQueue { get; }

    protected async override Task ExecuteAsync(CancellationToken stoppingToken)
    {
        while (false == stoppingToken.IsCancellationRequested)
        {
            var workItem = await TaskQueue.DequeueAsync(stoppingToken);
            try
            {
                await )workItem(stoppingToken);
            }
            catch (Exception ex)
            {
                this._logger.LogError(ex, $"Error occurred executing {nameof(workItem)}.");
            }
        }
    }
}

public interface IBackgroundTaskQueue
{
    void QueueBackgroundWorkItem(Func<CancellationToken, Task> workItem);

    Task<Func<CancellationToken, Task>> DequeueAsync(
        CancellationToken cancellationToken);
}

public class BackgroundTaskQueue : IBackgroundTaskQueue
{
    private ConcurrentQueue<Func<CancellationToken, Task>> _workItems =
        new ConcurrentQueue<Func<CancellationToken, Task>>();
    private SemaphoreSlim _signal = new SemaphoreSlim(0);

    public void QueueBackgroundWorkItem(
        Func<CancellationToken, Task> workItem)
    {
        if (workItem == null)
        {
            throw new ArgumentNullException(nameof(workItem));
        }

        _workItems.Enqueue(workItem);
        _signal.Release();
    }

    public async Task<Func<CancellationToken, Task>> DequeueAsync(
        CancellationToken cancellationToken)
    {
        await _signal.WaitAsync(cancellationToken);
        _workItems.TryDequeue(out var workItem);

        return workItem;
    }
}

Теперь мы можем безопасно ставить задачи в фоновом режиме, не влияя на время, необходимое для ответа на запрос.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...