Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Two parallel ajax requests to Action methods are queued, why?

I'm developing a video website using ASP.NET MVC.

One functionality I want to have in my application is transocding video. But as the transcoding process could be very time-consuming, I want to show the progress of that process to the client user.

So, my schema is to use one controller action to handle the whole transcoding process and write its progress into a file stored on the server. Meanwhile I use Ajax to call another controller action to read the specified file, retrieve the progress information and send it back to the client for display every 2 seconds during the transcoding process.

To fulfill my plan, I have written the following code:

Server Side:

public class VideoController : Controller
{
         //Other action methods
         ....
    //Action method for transcoding a video given by its id
    [HttpPost]
    public async Task<ActionResult> Transcode(int vid=0)
    {
        VideoModel VideoModel = new VideoModel();
        Video video = VideoModel.GetVideo(vid);
        string src = Server.MapPath("~/videos/")+video.Path;
        string trg = Server.MapPath("~/videos/") + +video.Id+".mp4";
        //The file that stores the progress information
        string logPath = Server.MapPath("~/videos/") + "transcode.txt";
        string pathHeader=Server.MapPath("../");

        if (await VideoModel.ConvertVideo(src.Trim(), trg.Trim(), logPath))
        {
            return Json(new { result = "" }); 
        }
        else
        {
          return Json(new { result = "Transcoding failed, please try again." });
        }
    }

    //Action method for retrieving the progress value from the specified log file
    public ActionResult GetProgress()
    {
        string logPath = Server.MapPath("~/videos/") + "transcode.txt";
        //Retrive the progress from the specified log file.
        ...
        return Json(new { progress = progress });
    }
}

Client Side:

var progressTimer = null;
var TranscodeProgress = null;

// The function that requests server for handling the transcoding process
function Transcode(vid) {
    // Calls the Transcode action in VideoController
    var htmlobj = $.ajax({
        url: "/Video/Transcode",
        type: "POST",
        //dataType: 'JSON',
        data: { 'vid': vid },
        success: function(data)
        {
        if(data.result!="")
            alert(data.result);
        }
        else
        {
          //finalization works
          ....
        }
    }
    });
    //Wait for 1 seconds to start retrieving transcoding progress
    progressTimer=setTimeout(function ()
    {
        //Display progress bar
        ...
       //Set up the procedure of retrieving progress every 2 seconds
        TranscodeProgress = setInterval(Transcoding, 2000);
    }, 1000);
}

//The function that requests the server for retrieving the progress information every 2 seconds.
function Transcoding()
{
    //Calls the GetProgress action in VideoController
    $.ajax({
        url: "/Video/GetProgress",
    type: "POST",
    //dataType: 'JSON',
    success: function (data)
    {
        if (data.progress == undefined || data.progress == null)
            return;
        progressPerc = parseFloat(data.progress);
        //Update progress bar
        ...
    }
  });
}

Now the Client-side code and the Transcode action method all work fine. The problem is that the GetProgress method will never get called until the Transcode action finishes its whole procedure. So what's wrong with my code? How can I modify it to make those two actions work spontaneously so as to achieve my goal?

Update

Based on Alex's answer, I found that my problem is caused by the session lock mechanism of Asp.Net framework. So disabling the SessionState of my VideoController or setting it as read-only does make the controller responses to the request for retrieving transcoding progress when the action method of transcoding video is being executed. But because I use Session in my VideoController to store some variables for use across multiple requests, this way couldn't be a suitable solution for my problem. Is there a better way to solve it?

like image 583
Ivan Avatar asked Nov 06 '16 09:11

Ivan


People also ask

How do I stop multiple Ajax calls from repeated clicks?

For example: If use ajax request in other ajax page, Using ajax in php loop, etc, Give you multiple ajax request with one result. I have solution: Use window. onload = function() { ... }

How do I send multiple Ajax requests at once?

If you had two server side page for your two AJAX files then it would be fine. Try to create two different aspx file for you different methods to have them called together.

How to handle multiple Ajax calls in JQuery?

The jQuery library provides a way to make any callback function waiting for multiple Ajax calls. This method is based on an object called Deferred. A Deferred object can register callback functions based on whether the Deferrred object is resolved or rejected.

Can we execute run multiple Ajax requests simultaneously in JQuery?

To iterate through the response, there is a callback function attached to it. This callback function gets executed once both the Ajax requests are finished. In case where multiple Deferred objects are passed to $. when() , it takes the response returned by both calls, and constructs a new promise object.

How do I run multiple Ajax requests in parallel?

Run multiple AJAX requests in parallel When working with APIs, you sometimes need to issue multiple AJAX requests to different endpoints. Instead of waiting for one request to complete before issuing the next, you can speed things up with jQuery by requesting the data in parallel, by using jQuery's $.when () function:

Is there a “deferred” way to get Ajax requests?

Or the “Deferred” way, this time using a shorthand $.get () method: But we have three Ajax requests we’re needing to perform, and we want to wait for all three of them to finish before doing anything, so it could get pretty gnarly in callback land:

How many Ajax requests do I Need?

So you decide that instead of having that HTML, CSS, and JavaScript on the page directly, you’re going to Ajax that stuff in when the feature is about to be used. We’ll need to make three Ajax requests.

Is it slow to make 3 requests at the same time?

It’s slow. One request … wait to be done … another request … wait to be done … another request … wait to be done … go. It would be faster if we could do: All three requests in parallel … wait for all three to be done … go.


2 Answers

You misunderstood the whole point about async/await. It doesn't change the fact that for each single request, there is a single response that is returned. When you call await in your action, nothing is returned to client yet. The only thing it does (in a very high level abstraction) is to release the current thread that handles this request to a thread pool so it could be used for processing other requests. So basically it allows you to use your server resources more efficiently since there are no threads that are wasted waiting for long I/O operations to complete. Once the I/O operation is completed the the execution of the action (that called for await) continued. Only at the end of an action the response is sent to the client.

As for you scenario, if it is a long running task, I would use some kind of background processing solution such as Hangfire and use SignalR to push updates from server.Here is an example

You can also implement something similar on your own (example).

UPDATE: As @Menahem stated in his comment I maybe misinterpreted part of your question.

Request queuing issue may be caused by incorrect configuration of SessionStateBehavior. Since MvcHandler handler which is used by ASP.NET MVC is marked with IRequiresSessionState interface, only one request at time could be processed per session. In order to change that, make you controller sessionless (or ar least make sure that you are not writing into session in this controller) and mark it with [SessionState(System.Web.SessionState.SessionStateBehavior.ReadOnly)] attribute.

like image 97
Alex Art. Avatar answered Oct 26 '22 01:10

Alex Art.


File creation is blocking call. In other words, until first thread will not close file, second one which makes report will not be able to read contents of that file. As workaround you can create files with percentage of progress. For example movie1-5-percent.txt, movie1-10-percent.txt, movie1-15-percent.txt etc, in order to avoid blocking calls to file system. Then you can check, if for movie1 there is file movie1-15-percent.txt, then you can report to ajax call, that 15 percent of movie was converted. Or choose another non blocking storage. For example you can report result to db in first thread, and read results from db in another.

like image 27
Yuriy Zaletskyy Avatar answered Oct 26 '22 02:10

Yuriy Zaletskyy