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

本文关键字:任务 网站 异步 用于 多线程 | 更新日期: 2023-09-27 18:24:22

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

所以当用户结账时,我有一个银行回调页面。。。

但是,由于我必须在付款后执行一项漫长的任务(目前是同步完成的),用户必须等待很长时间才能重定向回我的网站。

我试着用thread.start制作一个后台线程,但问题是我丢失了会话,这是不明显的。

那么,根据这一描述,您将如何进行?您选择异步还是多线程?

如果你选择异步,会怎么样?

所以我们有这样的东西:

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

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

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

您可以使用数据库来存储任务(并随着作业的进行更新其状态),也可以简单地创建一个执行作业的windows服务或类似服务。


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

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

可能会进行类似的操作

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 !
        }
    });
}

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

我会将冗长的操作放入队列(MSMQ、RabbitMQ等)中,并让工作进程(最好是windows服务器)将作业排成队列并执行这些冗长的操作。

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

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