Marcin Konrad Ceglarek
Marcin Konrad Ceglarek

Reputation: 1522

BackgroundWorker in MVC3 application freezes UI

I'm developing MVC3 based web application, which at one point needs to cache large amount of data from some external database. Process takes about 10-30 min (depending on a traffic) so I put it in BackgroundWorker. When you click particular button on the webpage, using ajax it just access other method in controller, depending on the returned value proper information is displayed on user interface.

Controller:

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

Model:

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

Now when I do update, UI still freezes. While debuging controller I can see, that it starts BackgroundWorker and instantly continues to return statement (with success = true), but then it just finishes, and nothing else happens (returned message never reaches webpage).

I can see page from other browser/user and everything works ok, but this particular thread is locked for several minutes (not entire 10-30 min, as it's get unlocked after about 5 min - timeout?)

My question is, what I did wrong and how to fix it. I expect backgroundWorker to just run in the background, and free user to move around page wherever he wish. Also making an entry in database and making some external application just fetch it and do all the work (in real background) is not an option for me.

Upvotes: 1

Views: 1471

Answers (2)

rouen
rouen

Reputation: 5124

Do not use Background worker like this. Yes, the work will be done within another thread, but still in scope of that web request. Web requests are not ment to be alive for 30 minutes, there are plenty of things that can go wrong (timeouts, app pool restart, other IIS behaviour..)

If you have this type of long-running task, you should do it in some worker - windows service, maybe console application, etc. and from web you just start it (console) or set it to be done (message queue, azure queue)

Also, i hope you are not locking database (you method IsDbLocked()) for 30 minutes? Just do your import in transaction and use proper isolation level (read commited) so DB work normally all the time and the changes are there instantly when import finishes.

Upvotes: 3

Varun K
Varun K

Reputation: 3638

I'm developing MVC3 based web application
... so I put it in BackgroundWorker

BackgroundWorker is designed to work with Windows (forms) application; to achieve similar in web application, use Task.Factory.StartNew or Thread (more primitive)

Upvotes: 2

Related Questions