Slender回答了我最初的问题,即在发送HTTP响应后,发生了什么事情,然后忘记了,但是现在我剩下的问题是如何正确地对后台任务进行排队
编辑
众所周知,except for in the case when it comes to event handlers通常是异步无效的,我想执行一些后台逻辑而不必等待客户端。我最初的想法是使用“火与忘了”
说我有一个活动:
public class SecondTestClass extends DriverFactory {
WebDriver driver;
然后有人订阅了一个“忘却”任务:
public event EventHandler LongRunningTask;
网络api方法是调用:
LongRunningTask += async(s, e) => { await LongNetworkOperation;};
但是,如果这样做,我不能保证长时间运行的任务能够完成,如何在不影响发出请求的时间的情况下处理正在运行的后台任务(例如,我不想等待该任务首先完成)?
答案 0 :(得分:12)
只想在@ johnny5答案中添加一些其他注释。现在,您可以使用https://devblogs.microsoft.com/dotnet/an-introduction-to-system-threading-channels/代替带有信号量的ConcurrentQueue。 该代码将是这样的:
public class HostedService: BackgroundService
{
private readonly ILogger _logger;
private readonly ChannelReader<Stream> _channel;
public HostedService(
ILogger logger,
ChannelReader<Stream> channel)
{
_logger = logger;
_channel = channel;
}
protected override async Task ExecuteAsync(CancellationToken cancellationToken)
{
await foreach (var item in _channel.ReadAllAsync(cancellationToken))
{
try
{
// do your work with data
}
catch (Exception e)
{
_logger.Error(e, "An unhandled exception occured");
}
}
}
}
[ApiController]
[Route("api/data/upload")]
public class UploadController : ControllerBase
{
private readonly ChannelWriter<Stream> _channel;
public UploadController (
ChannelWriter<Stream> channel)
{
_channel = channel;
}
public async Task<IActionResult> Upload([FromForm] FileInfo fileInfo)
{
var ms = new MemoryStream();
await fileInfo.FormFile.CopyToAsync(ms);
await _channel.WriteAsync(ms);
return Ok();
}
}
答案 1 :(得分:6)
.Net Core 2.1具有IHostedService,它将在后台安全运行任务。我在QueuedHostedService
的{{3}}中找到了一个示例,已对其进行了修改以使用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;
}
}
现在,我们可以在后台安全地将任务排队,而不会影响响应请求所花费的时间。