Async Controllers (MVC), long running process with “stops”

I’m interested in running a long process, I want to update the UI as soon as results start coming in and not wait for it to finish.

How would I go about this? I’ve read about Async controllers but they don’t seem to have anything built-in for this purpose.

Just save the results in the Application/Session object as the results come in and use polling from client side? I can think of several ways that could go wrong (like user closes page, and the object stays in Application object forever – need to manage expiration of these object myself, extra server-load for polling, etc).

Any thoughts?

Thank you

Answers:

Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.

Method 1

I was trying to solve something similar (reporting real-time progress from a long running server operation back to the client) recently and it turned out SignalR is a perfect fit for this situation.

Basically it is a library wrapping long-polling and Web Sockets, using (transparently) whatever is available on server and client.

I only have good experience with it so far.

Method 2

You can run the long running task using ThreadPool.QueueUserWorkItem and it can update state in Application/Session which the user can poll. As you pointed that has some lifetime issues. Beyond what you pointed out, the app-pool could recycle – but maybe that’s OK.

What is the logical scope of that operation? Is it a system type long running task that someone/many folks need to query the progress on? Or is it a long running task on behalf of a specific user? If it’s the latter, then it’s OK if that user’s session times out, etc… If it’s the former then you need to be more durable. for example, you could store the task request, the state and the progress in a database. That way on app restart it can just pickup where it eft off and its easy to query by anyone (a noter decision point if system level task).

The final consideration is whether you’ll ever have more than one web roles (web farm/cluster). If that’s ever a consideration than a DB or even separate worker role/service becomes more appropriate.

So it all boils down to the type of task it is, who needs to monitor it and what are the durability requirements. If its just a user task, keep it simple, queueuserworkitem and session state.

Method 3

This article seems to describe what you want, simple and w/o SignalR:

ASP.NET MVC 3: Async jQuery progress indicator for long running tasks

Controller:

public class HomeController : Controller
{
private static IDictionary tasks = new Dictionary();

 public ActionResult Index()
 {
   return View();
 }

 public ActionResult Start()
 {
   var taskId = Guid.NewGuid();
   tasks.Add(taskId, 0);

   Task.Factory.StartNew(() =>
   {
     for (var i = 0; i <= 100; i++)
     {
       tasks[taskId] = i; // update task progress
       Thread.Sleep(50); // simulate long running operation
     }
     tasks.Remove(taskId);
   });

   return Json(taskId);
 }

 public ActionResult Progress(Guid id)
 {
   return Json(tasks.Keys.Contains(id) ? tasks[id] : 100);
 }

}

View:

<script type="text/javascript">

function updateMonitor(taskId, status) {
  $("#" + taskId).html("Task [" + taskId + "]: " + status);
}

$(function () {
  $("#start").click(function (e) {
   e.preventDefault();
   $.post("Home/Start", {}, function (taskId) {

     // Init monitors
     $("#monitors").append($("<p id='" + taskId + "'/>"));
     updateMonitor(taskId, "Started");

     // Periodically update monitors
     var intervalId = setInterval(function () {
       $.post("Home/Progress", { id: taskId }, function (progress) {
         if (progress >= 100) {
           updateMonitor(taskId, "Completed");
         clearInterval(intervalId);
         } else {
           updateMonitor(taskId, progress + "%");
         }
       });
     }, 100);
   });
 });

});


All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

0 0 votes
Article Rating
Subscribe
Notify of
guest

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x