DEV Community

catrina
catrina

Posted on • Originally published at catrina.me on

Using Async, Await, Plus a Slight Delay?

Today’s problem dealt with how we view our invoices online. We use an app on the iSeries that creates a PDF and delivers it to a set destination. That destination, in our case is a regular windows server, the files landing in a small site: pdf.mycompany.com.

My initial approach was simple, use the PHP API I have sitting on the iSeries to make a call to the program – passing it the parameters for that specific invoice, await response (which gave me the new created filename) and then redirect to that URL. The method looks something like this:

[HttpGet]
public async Task<ActionResult> GetInvoiceAsync(int invoice)
{
    GetInvoice getInvoice = new GetInvoice();
    var client = new HttpClient();

    string fileName = await getInvoice.LoadPDF(invoice);

    string url = "http://pdf.mycompany.com/";
    url += fileName + ".pdf";

    return Redirect(url);
}
Enter fullscreen mode Exit fullscreen mode

This worked great… 90% of the time, but the other 10% of the time, I clicked too quickly on an invoice and got forwarded to a 404.

The Confusion

LoadPDF is an async method, sitting in my Services folder and the method above sits in my controller. I assumed, because it was an await, well, GetInvoiceAsync should WAIT until the server is done. So, then, why am I getting forwarded prematurely? Why is it not waiting?

The Real Problem

GetInvoiceAsync IS waiting, it is waiting for a response.

What was really happening:

  • LoadPDF takes data, seralizes it.
  • LoadPDF creates a HttpWebRequest and posts the data to the iSeries
  • The iSeries responds with a file name
  • RESPONSE IS MADE. AWAIT IS OVER
  • User is forwarded to new file
  • iSeries is still in the process of copying file over
  • User gets a 404

Easy Solution

I solved the problem by simply adding a small delay inside of LoadPDF. So, it gets response, then waits another 1.5 seconds before confirming to the controller it is done. Here’s the code that solved it:

//declared at top of class
CancellationTokenSource source = new CancellationTokenSource();

//iSeries needs time to copy file over to pdf server
//added in LoadPDF just before return(fileName);
await Task.Delay(TimeSpan.FromSeconds(1.5), source.Token);
Enter fullscreen mode Exit fullscreen mode

Do you know a better way I can handle this?

Top comments (2)

Collapse
 
joaofbantunes profile image
João Antunes

I guess it's a valid solution if you have no way to know when the PDF is available. The only problem is if for some unexpected reason it takes longer for the PDF to be available.

Maybe something like this could be useful?

var request = new HttpRequestMessage(HttpMethod.Head, url);
var response = await httpClient.SendAsync(request, cancellationToken);
//maybe limit the number of times this can be done
while (response.StatusCode != HttpStatusCode.OK)
{
    await Task.Delay(500, cancellationToken);
    response = await httpClient.SendAsync(request, cancellationToken);
}

It's basically polling the PDF url to check when it's available.

On a side note, how's that CancellationTokenSource being used? You're using it to cancel the execution given some event?

Collapse
 
catriname profile image
catrina

not currently, i cleaned it up! thanks for spotting it!