[英].Net Core Queue Background Tasks
在发送HTTP响应之后,Slender回答了我关于触发和忘记发生的事情的原始问题,但现在我留下了如何正确排队后台任务的问题
编辑
众所周知,Async void通常很糟糕, 除非涉及事件处理程序 ,我想执行一些后台逻辑而不必让客户端等待。 我最初的想法是使用Fire和Forget
说我有一个活动:
public event EventHandler LongRunningTask;
然后有人订阅了火灾并忘记了任务:
LongRunningTask += async(s, e) => { await LongNetworkOperation;};
web api方法是调用:
[HttpGet]
public async IActionResult GetTask()
{
LongRunningTask?.Invoke(this, EventArgs.Empty);
return Ok();
}
但如果我这样做,我的长期运行任务不能保证完成,我如何处理正在运行的后台任务而不影响我的请求所需的时间(例如我不想等待任务先完成)?
.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;
}
}
现在,我们可以安全地在后台排队任务,而不会影响响应请求所需的时间。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.