John Hughes
John Hughes

Reputation: 377

MVC 5 / .NET 4.5 - Long running process

I have a website on Rackspace which does calculation, the calculation can take anywhere from 30 seconds to several minutes. Originally I implemented this with SignalR but had to yank it due to excessive CC usage. Hosted Rackspace sites are really not designed for that kind of use. The Bill went though the roof.

The basic code is as below which work perfectly on my test server but of course gets a timeout error on Rackspace if the calculation take more than 30 seconds due to their watcher killing it. (old code) I have been told that the operation must write to the stream to keep it alive. In the days of old I would have started a thread and polled the site until the thread was done. If there is a better way I would prefer to take it.

It seems that with .NET 4.5 I can use the HttpTaskAsyncHandler to accomplish this. But I'm not getting it. The (new code) below is as I understand the handler you would use by taking the old code in the using and placing it in the ProcessRequestAsync task. When I attempt to call the CalcHandler / Calc I get a 404 error which most likely has to do with routing. I was trying to follow this link but could not get it to work either. The add name is "myHandler" but the example link is "feed", how did we get from one to the other. They mentioned they created a class library but can the code be in the same project as the current code, how?

http://codewala.net/2012/04/30/asynchronous-httphandlers-with-asp-net-4-5/

As a side note, will the HttpTaskAsyncHandler allow me to keep the request alive until it is completed if it takes several minutes? Basically should I use something else for what I am trying to accomplish.

Old code

[Authorize]
[AsyncTimeout(5000)] // does not do anything on RackSpace
public async Task<JsonResult> Calculate(DataModel data)
{
   try
   {
        using (var db = new ApplicationDbContext())
        {
           var result = await CalcualteResult(data);
           return Json(result, JsonRequestBehavior.AllowGet);
        }
   }
   catch (Exception ex)
   {
      LcDataLink.ProcessError(ex);
   }

   return Json(null, JsonRequestBehavior.AllowGet);
}

new code

public class CalcHandler : HttpTaskAsyncHandler
{
    public override System.Threading.Tasks.Task ProcessRequestAsync(HttpContext context)
    {
        Console.WriteLine("test");
        return new Task(() => System.Threading.Thread.Sleep(5000));
    }
  }

Upvotes: 2

Views: 832

Answers (1)

Roman Pushkin
Roman Pushkin

Reputation: 6089

It's not a best approach. Usually you need to create a separate process ("worker role" in Azure).

This process will handle long-time operations and save result to the database. With SignalR (or by calling api method every 20 seconds) you will update the status of this operation on client side (your browser).

If this process takes too much time to calculate, your server will become potentially vulnerable to DDoS attacks.

Moreover, it depends on configuration, but long-running operations could be killed by the server itself. By default, if I'm not mistaken, after 30 minutes of execution.

Upvotes: 0

Related Questions