MVC 5 共享长 运行 任务

MVC 5 Shared Long Running Task

我有一个很长的 运行 action/method,当用户单击内部 MVC5 应用程序上的按钮时调用它。该按钮由所有用户共享,这意味着第二个人可以在点击后几秒钟内进入并点击它。长 运行 任务正在通过 SignalR 向所有客户端更新共享任务 window。

是否有推荐的方法来检查任务是否仍然繁忙并简单地通知用户它仍在工作?还有另一种推荐的方法吗? (不能为工作使用外部 windows 服务)

目前我所做的似乎是一个坏主意,或者我可能是错的,但它是可行的。请参阅下面的示例,了解我正在做的事情。

public static Task WorkerTask { get; set; }
public JsonResult SendData()
{
    if (WorkerTask == null)
    {
        WorkerTask = Task.Factory.StartNew(async () =>
        {
            // Do the 2-15 minute long running job
        });

        WorkerTask = null;
    }
    else
    {
        TempData["Message"] = "Data is already being exported. Please see task window for the status.";
    }

    return Json(Url.Action("Export", "Home"), JsonRequestBehavior.AllowGet);
}

我认为你所做的根本行不通。我看到三个问题:

  1. 您正在将 WorkerTask 存储在控制器上(我认为)。为每个请求创建一个新的控制器。因此,将始终创建一个新的 WorkerTask
  2. 如果#1 不成立,您仍然需要将 WorkerTask 的实例化封装在一个锁中,因为多个客户端可以同时访问 WorkerTask == null 检查。
  3. 您的 Web 应用程序中不应该有很长的 运行 任务。应用程序池可能会随时重新启动,从而杀死您的 WorkerTask.

如果您想跳过 "don't do long running work in your web app" 的最佳实践建议,您可以使用 .NET 4.5.2 中引入的 HostingEnvironment.QueueBackgroundWorkItem 来启动漫长的 运行 任务。您可以在 HttpApplication.Cache 中存储一个变量,以指示长 运行 进程是否已启动。

这个解决方案有很多问题(它在网络场中不起作用,应用程序池可能会死掉,等等)。更强大的解决方案是使用 Quartz.net 或 Hangfire 之类的东西。