如何在ASP.NET Web API中排队后台任务

我有一个webapi,旨在以队列方式处理报告。 该应用程序采取的步骤如下:

  • 接收内容
  • 将内容映射到对象并将其放入队列
  • 轮询队列中的待处理项目
  • 一次处理队列中的项目

我当时正在考虑使用Entity Framework来创建排队项目的数据库,例如:

public class EFBatchItem { [Key] public string BatchId { get; set; } public DateTime DateCreated { get; set; } public DateTime DateCompleted { get; set; } public string BatchItem { get; set; } public BatchStatus Status { get; set; } } 

我的问题 – 是否有一种更有效的方法,使用NServiceBus,BlockingCollection或ConcurrentQeueue,而不是不断轮询数据库并逐个拉出待处理的项目? 我之前没有使用过队列。

一种想法是创建一个任务队列,并在一个单独的线程上处理所有挂起的任务。 有点类似于使用线程处理队列的最有效方法,但我想确保我走最有效的路线。

编辑:我在这里的一个重要问题是向用户显示进度的最佳方式。 一旦用户提交内容,他就会进入新页面,并可以按批次标识符查看状态。 MSMQ是必需的,还是NServiceBus,以便通知用户? 这似乎是REquest / Acknowledge / Push范式的变体?

恕我直言,您的ASP.NET Web API应用程序不应该自己运行这些后台任务。 它应该只负责接收请求,将其粘贴到队列中(如您所示)并返回指示接收消息成功或失败的响应。 您可以使用各种消息传递系统(如RabbitMQ)来实现此方法。

至于通知,您有几个选择。 您可以拥有一个客户端可以检查处理是否完成的端点。 或者,您可以提供客户端可以订阅的流API端点。 这样,客户端就不必轮询服务器; 服务器可以通知连接的客户端。 ASP.NET Web API有一个很好的方法。 以下博客文章解释了如何:

  • 使用ASP.NET Web API和Knockout.js进行原生HTML5推送通知

您还可以将SignalR视为此类服务器的客户端通知。

后台任务很难用于ASP.NET Web API应用程序的原因是您有责任保持AppDomain的活动。 这是一个麻烦,尤其是当您在IIS下托管时。 以下博客文章解释了我的意思:

  • 从ASP.NET请求尽早返回
  • 在ASP.NET中实现重复后台任务的危险

这是一个NuGet包,它被称为HangFire – https://github.com/HangfireIO/Hangfire 。 任务仍然存在于apppool回收之外。

我喜欢@Todd的解决方案。 只是为了完整起见,但还有另一个选项尚未提及:

 HostingEnvironment.QueueBackgroundWorkItem(cancellationToken => { // Some long-running job }); 

注意:

“当ASP.NET必须回收时,它将通知后台工作(通过设置CancellationToken),然后等待最多30秒才能完成工作。如果后台工作没有在该时间范围内完成,那么工作将神秘地消失。“

并避免在此处使用注入DbContext的服务方法,因为这不起作用。

资料来源: MariusSchulz和StephenCleary

如果您使用Asp.net Core,则可以使用IHostService 。