C#5 .NET MVC长异步任务,进度报告和全局取消

时间:2013-10-28 16:57:37

标签: asp.net-mvc task-parallel-library signalr c#-5.0

我使用ASP.Net MVC 5并且我有一个长时间运行的操作,它必须轮询webservices,处理数据并将它们存储在数据库中。

为此,我想使用TPL库来启动任务异步。

但我想知道如何做三件事:

  • 我想报告此任务的进度。为此我想到了SignalR
  • 我希望能够离开我开始执行此任务的页面,并能够报告整个网站的进展情况(从左侧的面板开始,但这没关系)
  • 我希望能够全局取消此任务(从我左侧的面板中)

我对所涉及的所有技术了解不少。但我不确定实现这一目标的最佳方法。

有人可以帮我解决最佳解决方案吗?

2 个答案:

答案 0 :(得分:10)

当用户可以离开启动工作的页面时,您希望运行长时间运行的工作,这意味着您需要“在后台”运行此工作。它不能作为常规HTTP请求的一部分执行,因为用户可以通过导航或关闭浏览器随时取消其请求。事实上,这似乎是一个关键的场景。

Background work in ASP.NET is dangerous.你当然可以把它拉下来,但要做到这一点并不容易。此外,工作进程可能出于多种原因退出(应用程序池回收,部署,计算机重新启动,计算机故障,堆栈溢出或不相关的线程上的OOM异常)。因此,请确保您的长期工作能够容忍在中途中止。你可以减少发生这种情况的可能性,但绝不排除这种可能性。

通过将所有工作包装在事务中,您可以在面对任意终止时使代码安全。这当然只有在您不会导致非交易副作用(如改变状态的Web服务调用)时才有效。这里不可能给出一般性答案,因为在任意终止的情况下实现安全在很大程度上取决于要完成的具体工作。

这是我过去使用过的一种可能的架构:

  • 当作业进入时,您将所有必要的输入数据写入数据库表并向客户报告成功。
  • 你需要一种方法来启动一名工人来完成这项工作。你可以立即开始一项任务。如果应用程序在添加工作项之后但在为其启动任务之前退出,您还需要定期检查以查找未启动的工作。让Windows任务计划程序每分钟在您的应用程序中调用一次秘密URL。
  • 当您开始处理作业时,您将该作业标记为正在运行,以便不会意外地再次拾取该作业。完成该工作,编写结果并将其标记为已完成。全部在一次交易中。当您的流程中途退出时,数据库将重置所有相关数据。
  • 将作业进度写入单独连接和单独事务的单独表行。浏览器可以轮询服务器以获取进度信息。您也可以使用SignalR,但我没有相关经验,我希望在任意终止的情况下恢复进度报告很难。
  • 取消将通过在进度信息行中设置取消标志来完成。应用程序需要轮询该标志。

也许您可以使用消息队列进行作业处理,但我总是谨慎使用它。要以事务处理方式处理消息,您需要MSDTC,它不支持SQL Server的许多高可用性解决方案。

您可能认为这种架构不是很复杂。它利用轮询来处理很多事情。轮询是一种原始技术,但它运作良好。它可靠且易于理解。它有一个简单的并发模型。

如果您假设您的应用程序永远不会在不合时宜的时间退出,那么架构会更加简单。但这不能假设。你不能假设在工作时间没有部署,并且不存在导致崩溃的错误。

答案 1 :(得分:8)

即使使用http worker对于执行长任务也是一件坏事我已经举了一个如何使用SignalR管理它的小例子:

在这个例子中你可以:

  • 开始任务
  • 查看任务进度
  • 取消任务

它基于:

  • twitter bootstrap
  • knockoutjs
  • signalR
  • C#5.0 async / await with CancelToken和IProgress

您可以在此处找到此示例的来源:

https://github.com/dragouf/SignalR.Progress

enter image description here