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

20

我有一个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或ConcurrentQueue的方法? 我以前没有使用过队列。

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

编辑: 我在这里有一个很大的问题,那就是向用户显示进度的最佳方法。一旦用户提交内容,他将被带到一个新页面,并可以通过批次标识符查看状态。 是否需要MSMQ或NServiceBus来通知用户? 这似乎是请求/确认/推送范例的变体?


我的解决方案是在写入数据库的代码部分加上一个“锁”语句。 - efkah
谢谢你的建议 - 我没有想到过,如果不是你的提醒,后面可能会出现很多问题 :) 你对排队方法有什么想法吗?我应该尝试使用BlockingCollection还是只使用常量数据库轮询?已经在问题中进行了快速编辑。 - appsecguy
4个回答

28

我的观点是,你的ASP.NET Web API应用程序不应该自己运行这些后台任务。它只需要负责接收请求,将其放入队列中(如您所示),并返回表示接收到消息成功或失败的响应。您可以使用各种消息系统,例如RabbitMQ来实现这种方法。

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

您还可以考虑SignalR来实现此类型的服务器到客户端通知。

ASP.NET Web API应用程序之所以难以处理后台任务,是因为您需要保持AppDomain活动状态。特别是在IIS下托管时,这是一个麻烦。下面的博客文章非常好地解释了我的意思:


1
@pendraggon87,您所说的“ASP.NET函数”是什么意思? - tugberk
@pendraggon87,我的做法是通过我的ASP.NET Web API应用程序获取数据,将详细信息放入队列中,然后让工作人员生成Word文档。对于通知,我会选择上述描述的其中一种选项。 - tugberk
谢谢!您会推荐使用BackgroundWorker来作为工作者吗?(我在处理队列等方面几乎没有经验。我目前只是将我的EF数据库中的项目作为队列,并根据哪些行具有待处理状态来使用数据库。) - appsecguy
@pendraggon87 嗯,做好你的调研工作,基于这个做决定,不要只听从我的话 :) 但是 RabbitMQ 是一个很强的候选项。它有一个官方的 .NET 客户端,以及一个社区驱动的客户端(EasyNetQ)。 - tugberk
我很乐意听取关于我正在开发的后台任务运行/排队服务的反馈意见。 http://sharphooks.net它涉及实现接口的单个方法,通过Web UI上传文件,然后通过HTTP POST发布新作业。 - cdeutsch
显示剩余2条评论

7

谢谢这个链接,我以前没见过,但可能正是我需要的! - Phil

2
我喜欢@Todd的解决方案。只是为了完整起见,但还有另一个选项尚未提到:
HostingEnvironment.QueueBackgroundWorkItem(cancellationToken =>
{
    // Some long-running job
});

注意:
当ASP.NET需要回收时,它会通知后台工作(通过设置CancellationToken),然后等待最多30秒以完成工作。如果在该时间范围内后台工作未能完成,则该工作将神秘地消失。
同时,避免在此处使用带有注入DbContext的服务方法,因为这不起作用。
来源: MariusSchulzStephenCleary

1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接