【问题标题】:Fire and Forget with ASP.NET MVC使用 ASP.NET MVC 一劳永逸
【发布时间】:2011-09-16 12:29:54
【问题描述】:

我正在寻找关于火灾的最佳实践的信息,忘记了 asp.net mvc 操作......基本上我希望移动客户端拨打电话;服务器启动异步任务;然后尽快返回手机客户端。

但我想确保,假设没有例外,异步任务将成功完成。显然有几个不同的选择:

  • 创建一个新线程
  • 在 ThreadPool 上排队工作项
  • 开始异步委托调用
  • 开始任务

我认为任务将是这里的最佳选择,但想从 SO 那里得到想法。

编辑: 已根据一些答案进行澄清:客户不需要响应。我希望服务器开始异步任务后尽快完成 HTTP 请求。我知道客户端上的异步模式,但是我想限制移动设备保持连接打开所需的时间。此外,要避免有一个单独的进程来轮询或推送消息(通过队列、总线等),因为这太过分了。我只想在数据库中记录一些东西,客户端不需要在 IO 完成之前保持连接。

【问题讨论】:

    标签: asp.net-mvc asynchronous task-parallel-library


    【解决方案1】:

    我知道这是一个老问题,但这是我对这些事情的看法,因为它的价值,因为我不同意接受的答案。

    您不需要AsyncController,因为您对等待异步操作完成不感兴趣。因此,关于 MVC 方面的问题的答案是:没关系。您可以以任何方式完成您的工作,只需一个常规的旧操作即可启动流程并返回您想要的任何结果。

    您问题的第二部分确实更相关。您希望确保您的异步任务不会发生任何事情,因为您已经从 Web 进程启动它们,假设任务本身不会引发异常。答案取决于您的可靠性要求。

    您提到您不想要一个单独的流程,这限制了您的选择。您的任务将与您的 Web 应用程序在同一个应用程序域中运行。如果有任何事情导致应用程序域或进程崩溃,您的任务就会死掉,可能会处于一种奇怪的状态。这甚至不一定来自未处理的异常。 IIS 可以设置为不时或在某些条件下自动回收应用程序。或者如果你发布新代码或触摸 bin 目录中的任何内容,在所有请求完成后,你的应用程序域将被拆除,并启动一个新的。如果这些案例对您来说是一个阻碍,那么您别无选择,只能将您的任务移出进程并通过某种消息进行通信。

    如果您不担心 IIS 会杀死您,那么您仍然需要担心自己。如果您没有最后机会使用AppDomain.UnhandledException 事件处理来自其他后台任务的未处理异常,则会导致进程停止。在使用任务并行库的情况下,如果您没有通过Waiting 或查看Result 或Exception 属性未观察到的异常,那么如果您没有最后机会,任务将降低进程在TaskScheduler.UnobservedTaskException 事件中观察它们。

    另外需要注意的是,用于后台操作的任何 ThreadPool 线程在此期间都无法为您的 Web 应用程序提供请求。您可以管理池中的最大线程数,或者启动一个新线程。或者,如果您将 TPL 与默认调度程序一起使用,请使用 LongRunning 提示调度任务以有效地获得新线程。

    【讨论】:

      【解决方案2】:

      使用 TPL 和 Mvc 4 更清洁的射击和忘记

      public async Task<ActionResult> Index() 
      {
        // Start all operations.
        var tasks = new[]
        {
          Task.Run(() =>TestOutput.DoWork("1")), 
          Task.Run(() =>TestOutput.DoWork("2")), 
          Task.Run(() =>TestOutput.DoWork("3"))
        };
      
        // Asynchronously wait for them all to complete.
      // Uncomment below line to not forget the results
      //  var results = await Task.WhenAll(tasks);
      
        // Return empty string for fire and forget.
        return View(string.Empty);
      } 
      

      【讨论】:

      • 为了更清楚,这里的 Index 是控制器方法,需要被解雇和忘记 :) 。 TestOutput.DoWork(string var) 是将在服务器端运行的长时间运行的任务。它可以是任何服务器端方法
      【解决方案3】:

      你是矛盾的

      您的问题标题明确表示“一劳永逸”,然后在您的问题中提到相反的内容

      基本上我想要一个移动客户端拨打电话;服务器启动异步任务; 然后尽快返回到移动客户端。

      那么,您想要一个 async 调用 来返回结果,还是一个 Fire and forget 调用?


      如果是普通的异步调用,只需使用与您最喜欢的 javascript 库中相同的 jQuery .ajax() 方法,并在 success 属性函数中连接您的返回。


      如果发生火灾而忘记,最好的方法是让服务器在数据库中的TBL_JOBS 表中插入一行,然后您可以有一个循环脚本来选择它并处理信息。

      【讨论】:

      • 我的错误,因为我似乎不清楚,我不希望向客户返回响应。我只希望客户端进行 http 调用,服务器开始工作,然后不等待该工作完成,结束 http 响应。我也希望避免单独的工作/流程
      【解决方案4】:

      我建议使用AsyncController。您应该查看 Brad Wilson 的 Advanced MVC3 演示文稿的示例代码中的 AsyncController 区域,地址为 http://bradwilson.typepad.com/presentations/advanced-mvc-3.zip

      【讨论】:

      • 使用异步控制器,客户端仍然等待任务的最终完成,然后才认为 http 请求完成。我希望 http 调用几乎立即完成并返回到客户端
      • @Joel Martinez,AFAIK,如果您不需要将结果发送给客户端,则不必让异步操作等待操作完成。我没有深入研究代码,但我不明白为什么你必须等待异步操作完成。
      • 据我了解(我可能是错的),异步操作更多是为了简化服务器处理请求的方式。在 IO 绑定活动期间释放管道以处理来自其他客户端的其他请求。所以我认为它必须与已完成的操作配对,并且客户端的 http 连接在整个持续时间内都保持活动状态......不过我很想被证明是错误的 :-)
      • @Joel Martinez,虽然严格来说这不是我所说的 kosher,但您可以从被调用的例程中调用 AsyncManager.Finish(),您的 ...Completed() 方法将立即启动。跨度>
      猜你喜欢
      • 1970-01-01
      • 2016-07-20
      • 2017-06-16
      • 1970-01-01
      • 1970-01-01
      • 2016-09-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多