我正在开发基于MVC3的Web应用程序,它一度需要从一些外部数据库缓存大量数据。过程大约需要10-30分钟(取决于流量),所以我把它放在BackgroundWorker中。当您单击网页上的特定按钮时,使用ajax只需访问控制器中的其他方法,具体取决于返回的值,用户界面上会显示正确的信息。
控制器:
if (IsDbLocked())
{
return this.Json(new
{
success = false,
message = "There is already an update requested by other user on the way."
});
}
this.model.DataUpdateBegin();
return this.Json(new { success = true });
型号:
public void DataUpdateBegin()
{
var backgroundWorker = new BackgroundWorker
{
WorkerSupportsCancellation = false,
WorkerReportsProgress = true
};
backgroundWorker.DoWork += this.DataUpdateWorkerDoWork;
backgroundWorker.ProgressChanged += this.DataUpdaterWorkerProgressChanged;
backgroundWorker.RunWorkerCompleted += this.DataUpdaterWorkerRunWorkerCompleted;
if (this.DataUpdateLockDb(true))
{
backgroundWorker.RunWorkerAsync();
}
}
现在,当我更新时,UI仍然会冻结。虽然调试控制器我可以看到,它启动BackgroundWorker并立即继续返回语句(成功= true),但它刚刚完成,没有其他事情发生(返回的消息永远不会到达网页)。
我可以看到来自其他浏览器/用户的页面,一切正常,但这个特定的线程被锁定几分钟(不是整个10-30分钟,因为它在大约5分钟后解锁 - 超时?)
我的问题是,我做错了什么以及如何解决它。我希望backgroundWorker能够在后台运行,并且让用户可以随时随地移动页面。在数据库中创建一个条目并使一些外部应用程序只需获取它并完成所有工作(在实际背景中)对我来说不是一个选项。
答案 0 :(得分:3)
不要像这样使用Background worker。是的,工作将在另一个线程内完成,但仍在该Web请求的范围内。 Web请求不会活30分钟,有很多东西可能出错(超时,应用程序池重启,其他IIS行为......)
如果你有这种长期运行的任务,你应该在一些工作 - 窗口服务,可能是控制台应用程序等,并从网络你只是启动它(控制台)或设置它完成(消息队列) ,天蓝色队列)
另外,我希望你没有锁定数据库(你的方法IsDbLocked())30分钟?只需在事务中导入并使用适当的隔离级别(读取提交),这样DB就会一直正常工作,导入完成后会立即进行更改。
答案 1 :(得分:2)
我正在开发基于MVC3的Web应用程序
中
...所以我把它放在BackgroundWorker
BackgroundWorker旨在与Windows(表单)应用程序一起使用;要在Web应用程序中实现类似,请使用Task.Factory.StartNew或Thread(更原始)