我知道有很多API可以做到这一点,但我也知道托管环境(是ASP.NET)会对你在一个单独的线程中可靠地做的事情施加限制。
我可能完全错了,所以如果我是,请纠正我,但这是我认为我知道的。
如果你必须创建一个简单可靠且理论上可以运行长时间运行任务的编程模型,那么你将如何在ASP.NET应用程序中实现这一目标?
以下是我对此问题的看法:
我一直在考虑在win32服务中托管WCF服务。并通过WCF与服务部门交谈。然而,这不是很实用,因为我选择这样做的唯一原因是从几个不同的网络应用程序发送任务(工作单元)。然后我最终会询问服务状态更新并采取相应措施。我最担心的是,如果我必须将每个任务部署到服务中以便能够执行某些指令,那么这将不是特别好的体验。还有这个输入问题,如果我有一个庞大的数据集并且需要咀嚼它,我将如何用数据提供这个服务呢?
我现在通常做的就是这个
SELECT TOP 10 *
FROM WorkItem WITH (ROWLOCK, UPDLOCK, READPAST)
WHERE WorkCompleted IS NULL
它允许我将SQL Server数据库用作工作队列,并使用此查询定期轮询数据库以进行工作。如果工作项目成功完成,我将其标记为已完成并继续,直到没有其他任何操作。我不喜欢的是理论上我可以在任何时候中断,如果我在中间成功并将其标记为已完成,我可能最终会处理相同的工作项两次。我可能有点偏执,这可能都很好,但据我所知,并不能保证不会发生......
我知道之前有过类似的问题,但非确切的回答是肯定的答案。这是一个非常常见的事情,但ASP.NET托管环境无法处理长时间运行的工作。
请分享您的想法。
答案 0 :(得分:5)
NServiceBus是一个开源的 .NET的通信框架 建立对发布/订阅的支持 和长期运行的过程。
这是一种基于MSMQ的技术构建,这意味着您的消息不会丢失,因为它们会持久保存到磁盘。然而,该框架具有令人印象深刻的性能和直观的API。
答案 1 :(得分:3)
约翰,
我同意ASP.NET不适合您所描述的异步任务,也不应该。它被设计为一个网络托管平台,而不是后台处理器。
过去我们遇到过类似情况,我们使用的解决方案类似于您所描述的解决方案。总之,将您的WCF服务保留在ASP.NET下,使用带有Windows服务的“队列”表作为“QueueProcessor”。客户端应该轮询以查看是否已完成工作(或使用消息传递来通知客户端)。
我们使用了一个包含流程及其信息的表(例如InvoicingRun)。在该表上是一个状态(Pending,Running,Completed,Failed)。客户端将提交状态为Pending的新InvoicingRun。 Windows服务(处理器)将轮询数据库以获取处于挂起阶段的任何运行(您也可以使用SQL通知,因此您不需要轮询。如果找到挂起的运行,它会将其移动到运行状态,进行处理,然后将其移至已完成/失败。
如果进程失败致命(例如DB down,进程被杀死),则运行将保持运行状态,并且需要人工干预。如果进程在非致命状态(异常,错误)中失败,则该进程将被移至失败状态,您可以选择重试或进行人工干预。
如果有多个处理器,第一个将其移动到运行状态的处理器就可以完成这项工作。您可以使用此方法来防止作业运行两次。替代是执行select然后更新以在事务下运行。确保在交易之外的其中任何一个更大的交易。示例(粗略)SQL:
UPDATE InvoicingRun
SET Status = 2 -- Running
WHERE ID = 1
AND Status = 1 -- Pending
IF @@RowCount = 0
SELECT Cast(0 as bit)
ELSE
SELECT Cast(1 as bit)
罗布
答案 2 :(得分:0)
是否考虑过使用Workflow Foundation而不是自定义实现?它还允许您持久化状态。在这种情况下,任务可以定义为工作流程。
只是一些想法......
迈克尔
答案 3 :(得分:0)
使用简单的后台任务/作业框架,例如Hangfire,并将这些最佳实践原则应用于解决方案其余部分的设计: