多线程或异步用于网站中的长任务
本文关键字:任务 网站 异步 用于 多线程 | 更新日期: 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