1

我正在开发基于 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();
        }
    }

现在当我更新时,用户界面仍然冻结。在调试控制器时,我可以看到,它启动了 BackgroundWorker 并立即继续返回语句(成功 = true),但随后它就完成了,没有其他任何事情发生(返回的消息永远不会到达网页)。

我可以从其他浏览器/用户看到页面并且一切正常,但是这个特定的线程被锁定了几分钟(不是整个 10-30 分钟,因为它在大约 5 分钟后被解锁 - 超时?)

我的问题是,我做错了什么以及如何解决它。我希望 backgroundWorker 只在后台运行,并且让用户可以自由地在页面上随意移动。在数据库中创建一个条目并让一些外部应用程序获取它并完成所有工作(在真实背景中)对我来说不是一个选择。

4

2 回答 2

3

不要像这样使用后台工作人员。是的,这项工作将在另一个线程中完成,但仍在该 Web 请求的范围内。Web 请求不会存活 30 分钟,有很多事情可能会出错(超时、应用程序池重启、其他 IIS 行为..)

如果您有这种类型的长时间运行的任务,您应该在一些工作人员中执行 - Windows 服务,可能是控制台应用程序等,并且您只需从 Web 启动它(控制台)或将其设置为完成(消息队列,天蓝色队列)

另外,我希望你没有锁定数据库(你的方法 IsDbLocked())30 分钟?只需在事务中进行导入并使用适当的隔离级别(已提交读取),以便数据库始终正常工作,并且在导入完成时立即进行更改。

于 2013-08-16T14:56:59.797 回答
2

我正在开发基于 MVC3 的 Web 应用程序
......所以我把它放在 BackgroundWorker

BackgroundWorker 旨在与 Windows(窗体)应用程序一起工作;要在 Web 应用程序中实现类似的功能,请使用Task.Factory.StartNewThread(更原始)

于 2013-08-16T14:13:36.967 回答