Aysnc Await

The async/await operators have been around for some time (since C# 5.0, introduced in 2012) and have been of substantial use. A question about their use arises however: Why aren’t they used for every function? One of the reasons I believe is that they make debugging a bit tougher, and if you are not hurting for threads, why not just make your function synchrounous?

It seems as though I have gotten burned for not using these in a proper way. Most of the time, you can afford to make code synchronous, but recently we at AACN had a major increase in traffic due to the release of a free COVID-19 course.

In our code that receives these updates I put in the following line:

var response = _coursesService.ForwardCourseUpdatesToMicroservice(myDecodedString).Result;

Notice the “.Result” . This forces the code to block until the function completes, even though it is an asynchronous function.

Full code block:

    public async Task<HttpResponseMessage> ForwardCourseUpdatesToMicroservice(string requestString)
    {

        rspRegistrationreport request;

        using (var reader = new StringReader(requestString))
        {
            XmlRootAttribute xRoot = new XmlRootAttribute();
            xRoot.ElementName = "registrationreport";
            xRoot.IsNullable = true;

            var serializer = new System.Xml.Serialization.XmlSerializer(typeof(rspRegistrationreport), xRoot);
            request = (rspRegistrationreport)serializer.Deserialize(reader);
        }

var response = _coursesService.ForwardCourseUpdatesToMicroservice(myDecodedString).Result;


            var rspJson = JsonConvert.SerializeObject(request);

            var message = new HttpRequestMessage();

            var httpContent = new StringContent(rspJson, Encoding.UTF8, "application/json");

            message.Content = httpContent;
            message.RequestUri = new Uri(_serviceUrl + "/api/courses/progressupdate");

            var webClient = new HttpClient();

            HttpResponseMessage response;


            using (HttpClient client = new HttpClient())
            {
                response = await client.PostAsync(new Uri(_serviceUrl + "/api/courses/progressupdate"), httpContent);
            }

            return response;
        }
}

What this code does is take a response, parsse it, and forward it on to another microservice.

In my debugging, I referenced the .Result construct to have the code run synchronously, mostly to save time debugging. The problem was, when load on this function increased to 40 calls/sec, there weren’t enough available threads to handle new requests. This is illustrated in the following diagram:

Synchronous Time, Fig 1

By removing the following .Result from the code above, you can cut the time down substantially, so the gateway web service can service additional requests, and a thread is not locked up waiting on an external micro service, which in turn is waiting for a database:

Asynchronous Time, Fig 2

What a way to free up resources, all from changing a single line of code!