多线程或异步,用于网站中的冗长任务

时间:2013-07-22 19:29:55

标签: c# asp.net-mvc-4

我目前正在运营一个电子商务网站。

因此,当用户结帐时,我有一个银行回拨页面...

但由于我必须在付款发生后执行冗长的任务(目前同步完成),因此用户必须等待很长时间才能将其重定向回我的网站。

我试图用thread.start创建一个后台线程,但问题是我松开了会话,这是不可理解的。

那么,基于这个描述,你将如何进行?你会去异步还是多线程?

如果你去Async,会怎么样?

所以我们有类似的东西:

public ActionResult CallBack()
{
    if (AcceptPayment() == "OK")
    {
      LenghtyTask(); 
    }

    return RedirectToUrl("MyWebSite");   
} 

3 个答案:

答案 0 :(得分:3)

首先,在ASP.NET站点中运行后台线程是一个很大的禁忌,因为您无法控制应用程序的生命周期。应用程序池可以关闭或回收,这意味着您丢失了数据。

您可以使用数据库来存储任务(并在作业进行时更新其状态),或者只是创建一个执行作业的Windows服务或类似服务。


由于您无法控制正在运行的作业,因此询问您是否应使用Async或线程是毫无意义的,因为它们都不会释放任何资源(即使您的应用程序运行得更快)。

只需选择您知道的那个并让HTTP请求完成即可。告诉用户该作业正在后台处理,让他刷新浏览器以查看其进展情况。另一种方法是使用Ajax或ASP.NET SignalR来检查后台进度。

答案 1 :(得分:0)

可能会像这样

public ActionResult CallBack()
{
    if (AcceptPayment() == "OK")
    {
        // simply launches the task and moves on
        Task.Run(LenghtyTask()); 
    }

    return RedirectToUrl("MyWebSite");   
} 

现在在您的页面上:RedirectToUrl(“MyWebSite”)

你必须设置像Tejs指出的ajax请求,它可以在任务完成时通知用户

public ActionResult IsTaskFinished()
{
    // No clue where your transaction is, but your gonna need to know it to check it's state
    return JSON(SomeClass.Current.IsTaskFinished(ContextBoundObject.Transaction.Id));
} 

在实际启动ajax之前,您可能想在/ MyWebSite上调用SomeClass.Current.IsTaskFinished(ContextBoundObject.Transaction.Id) ..如果转换已经完成。

function isTaskFinished() {
    $.post("/IsTaskFinished").always(function(data) {
        if (!!data) {
            setTimout(isTaskFinished, 3000);
        }
        else {
            // yay i'm done, inform user !
        }
    });
}

当然,您必须考虑重试限制,错误处理等。

答案 2 :(得分:-1)

我会将冗长的操作放在队列中(MSMQ,RabbitMQ等),并让工作进程(最好是Windows服务器)将作业出列并执行那些冗长的操作。

就如何通知用户而言,有几种选择,但我的选择是实时更新,您可以将服务器推送到客户端浏览器。只需在应用程序上有一个SignalR端点,然后通过工作进程上的SignalR .NET客户端连接它。完成冗长的操作后,您可以通过SignalR端点通知连接的客户端。

无论你做什么,都要避免在ASP.NET下进行任何数据关键操作的后台操作,如@jgauffin指出的那样。原因如下:http://haacked.com/archive/2011/10/16/the-dangers-of-implementing-recurring-background-tasks-in-asp-net.aspx