0

The scenario

I need to show N reports on a web page. The reports need to be requested to an external service. The time for the service to generate a report can vary from 2 seconds to 50 seconds, depending on the requested content.

To call the service I use HttpClient in an async action. To generate 1 report I call the service once. To generate 5 reports I call it 5 times and so on.

The Problem

Let's suppose we request 3 reports BigReport, MediumReport and SmallReport with a known relative generation time of 1 minute, 30 seconds and 2 seconds, and we call the service in the following order:

BigReport, MediumReport, SmallReport

The result of the HttpCalls will be as following:

  • HttpCall response for BigReport returns SmallReport (which is the quickest to be generated)
  • MediumReport will be correct
  • SmallReport response will contain the BigReport (which is the longest and the last)

Basicly, although the HttpCalls are different, for the fact they are made over a very short period of time, and they are still "active", the server will repond based on first arrived, first served, instead of serving each call with its exact response.

The Code

I have a Request controller with an async action like this:

public async Task<string> GenerateReport(string blockContent)
{
    var formDataContent = new MultipartFormDataContent
    {
        AddStringContent(userid, "userid"),
        AddStringContent(passcode, "passcode"),
        AddStringContent(outputtype, "outputtype"),
        AddStringContent(submit, "submit")
    };

    var blockStream = new StreamContent(new MemoryStream(Encoding.Default.GetBytes(blockContent)));
    blockStream.Headers.Add("Content-Disposition", "form-data; name=\"file\"; filename=\"" + filename + "\"");
    formDataContent.Add(blockStream);

    using (var client = new HttpClient())
    {
        using(var message = await client.PostAsync(Url, formDataContent))
        {
             var report = await message.Content.ReadAsStringAsync();

             return report;
        }
    }
}

The action is being called from a view via Ajax, like this

//FOREACH BLOCK, CALL THE REPORT SERVICE
$('.block').each(function(index, block) {

    var reportActionUrl = "Report/GenerateReport/"+block.Content;

    //AJAX CALL GetReportAction
    $(block).load(reportActionUrl);

});

Everything works fine if I covert the action from async to sync, by removing async Task and instead of "awaiting" for the response, I just get result as

var result = client.PostAsync(Url, formDataContent).Result.

This will make everything run synchronously and working fine, but the waiting time for the user, will be much longer. I would really like to avoid this by making parallel calls or similar.

Conclusions and questions

The problem itself make sense, after inspecting it also with Fiddler, as we have multiple opened HttpRequests pending almost simultaneously. I suppose I need a sort of handler or something to identify and match request/response, but I don't know what's the name of the "domain" I need to look for. So far, my questions are:

  • What is the technical name of "making multiple http calls in parallel"?
  • If the problem is understandable, what is name of the problem? (concurrency, parallel requests queuing, etc..?)
  • And of course, is there any solution?

Many thanks.

znn
  • 459
  • 7
  • 15
  • Normally, the calls should be parallel regardless of whether you use sync or async IO. They are parallel because the requests are independent and nothing serializes them. How can you tell the requests are not processed in parallel? Your Fiddler test seems to show the opposite. – usr Dec 10 '15 at 13:12
  • Or is the problem that the responses are mixed up? In that case the report service you are calling is broken. Post its code. Use Fiddler to make sure that it returns bad results. – usr Dec 10 '15 at 13:13
  • The problem is that the responses are mixed up. Fiddler shows clearly this problem. So do you think that is not a normal behaviour? Then, if I remove the async behavior, there is a sort of "deadlock" and the application waits for the first call to be completely finished, before starting the second one. Doing this the responses are not mismatched. I hope it makes sense. – znn Dec 10 '15 at 14:18
  • What system mixes up the responses? I understand there are two services here. – usr Dec 10 '15 at 14:35
  • Can you write that what $reportBlock.load is looking like? What it is doing, how is it making ajax requests and filling in data? – mehmet mecek Dec 10 '15 at 14:42
  • I forgot to correct the syntax (now corrected). It is a jQuery shorthand ajax call: http://api.jquery.com/load/ – znn Dec 10 '15 at 16:12
  • For usr, the system mixing up the responses is the external service – znn Dec 10 '15 at 16:16
  • Then you (obviously?) need to fix the external service. Do you agree? – usr Dec 13 '15 at 13:22
  • The point is that I don't have any kind of power over the external service. It belongs to another company, which, before disturbing that for such a weird issue, we need to try out any possible thing. – znn Dec 13 '15 at 14:07
  • The very good news is that, in the meantime, I've found out the problem which I will post it as soon as possible, and it was very much simpler than I thought. – znn Dec 13 '15 at 14:13

1 Answers1

0

With a "bit" of delay, I post the solution.

The problem was that the filename parameter was incorrectly called filename instead of blockname. This was causing the very weird behaviour, as a file could have had many blocks.

The lesson learned was that in case of very weird behaviour, in this case with a HttpClient call, analyse all the possible parameters and test it with different values, even if it doesn't make too much sense. At worst it can throw an error.

znn
  • 459
  • 7
  • 15