10

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

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

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

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

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

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

4

2 回答 2

10

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

ASP.NET 中的后台工作很危险。你当然可以成功,但要做到正确并不容易。此外,工作进程可能因多种原因退出(应用程序池回收、部署、机器重启、机器故障、堆栈溢出或无关线程上的 OOM 异常)。因此,请确保您的长期工作能够容忍中途中断。您可以减少发生这种情况的可能性,但永远不要排除这种可能性。

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

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

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

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

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

如果您可以假设您的应用程序永远不会在不合时宜的时间退出,那么架构会简单得多。但这不能假设。您不能假设在工作时间内不会进行部署,并且不会存在导致崩溃的错误。

于 2014-05-28T13:20:29.130 回答
8

即使使用 http worker 对运行长任务来说是一件坏事,我也做了一个小例子来说明如何使用 SignalR 管理它:

在此示例中,您可以:

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

它基于:

  • 推特引导
  • 淘汰赛
  • 信号R
  • 带有 CancelToken 和 IProgress 的 C# 5.0 异步/等待

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

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

在此处输入图像描述

于 2014-06-02T11:05:44.543 回答