Consequences of not awaiting - .net-5

I have a .net webapi that has some code to send emails.
public async Task CheckOut(CheckOutData checkOutData){
...
...
...
//What are the risks if I remove the await
await SendEmail(checkOutData);
...
...
}
public async Task SendEmail(CheckOutData checkOutData)
{
try{
...
...
...
}
catch (exception ex){
//log Error
}
}
I have setup logging in the SendEmail code. My question is, if I remove the await, is it possible for the thread to be killed and the email not being sent if the execution completes before the SendEmail completes?
Am I safe if I remove the await? I am willing to accept that an exception will be swallowed, it will be logged.

The email will be sent unless the entire process stops.
Regarding threads, we can divide SendEmail to two parts:
SendEmail
// Code that will run on the calling thread. This is the code that will prepare the data and send it to the hardware.
// Code that will run on a thread-pool thread. This is the code that will run after the hardware will finish sending the message.
The first part of the method will hold the original thread so the thread will not be released before it will finish. The second part will run on a thread-pool thread so it doesn't matter if the original thread was released.
EDIT:
If you are hosting your application on IIS, the app domain maybe recycled so it's not advised to run code that last the request. It's described in this blog post https://blog.stephencleary.com/2012/12/returning-early-from-aspnet-requests.html
In the self-hosting case this feature doesn't exist (Application pool recycling with Selfhosting a ASP.NET application). So you can just run a long running process by using Task.Run
Long running task in ApiController (using WebAPI, self-hosted OWIN)
So in the self hosting case you can avoid the await. The part of your method that you won't wait for won't be killed. As in the Task.Run case described above.
Hope this helps

Related

How can you publish using the ConsumeContext<T>() when using IReceiveObserver

When consuming faults implementing the IReceiveObserver, we are unable to publish via the ConsumeContext.Publish() method? The published messages aren't being received, what could be missing?
public Task ConsumeFault<T>(ConsumeContext<T> context, TimeSpan elapsed, string consumerType, Exception exception) where T : class
{
// called when the message is consumed but the consumer throws an exception
context.Publish(new {...}); //--> Doesn't publish the msg
}
To provide some context, we are firing off long running jobs and maintain a job dashboard to view their current status. Process flow is CreateJob->Send JobMessage-> JobConsumer receives and executes the task-> UpdateJob. All jobConsumer faults are being handled appropriately. In order to monitor Bus faults, we are looking to use the observers, so as to handle serialization/configuration errors etc. Aside from logging these faults, would also want to update the job state so that the dashboard would reflect the appropriate state. The IReceiveObserver receives the fault, however we would like to publish it to a central consumer to handle the updates as well. What am I missing?
For posterity was able to address this by registering an generic Fault consumer i.e IConsumer. As job context was in the message headers further actions were taken appropriately. Thank you Chris Patterson for the "MassTransit Commute - Consuming Fault Events" video!

Background processing on C# web api controller

I'm new on .NET technology and come into some problem. Currenlty i'm trying to build a REST API that handle long processing before sending the result to client.
What i'm trying to achieve is, i would like to do a background processing after receiving request from client. But, i would also like to send a response to client.
In short, it would be something like this.
Client Request -> Handled by controller ( doing some processing ) -> send response directly, ignoring the background that still running.
On Java, i can do this using Runnable Thread. How can i achieve this on C# Web API ?
Thank you.
In short, don't do this.
The job of an API is not to perform heavy duty, long running tasks.
You could simply let the API receive the request to perform something, then delegate that to another service. The API can then send a 200 response to show it received the request and maybe a URL to another resource which allows a user to track the progress.
The API needs to be available and responsive at all times. It needs to serve a number of users and if a number of them all request something that uses a lot of resources and takes a lot of time, chances are the API will simply go down and not serve anyone.
This is why you do not do such things in an API. Let other services do the heavy lifting.
Your api can call another async method and return 200/OK response without waiting for the request to complete.
You can learn more about async programing in c#.
static async Task Main(string[] args)
{
Console.WriteLine("coffee is ready");
var toastTask = MakeToastWithButterAndJamAsync(2);
async Task<Toast> MakeToastWithButterAndJamAsync(int number)
{
//Do something here.
}
}
This can be achieve this using loosed coupled architecture, by introducing service bus or blob storage, once you receive request in web api you can save it to blob/service bus and return acknowlegement response from web api. From service bus/blob storage use webjob/function/ durable function app to process the message using event.

Twilio Worker in Task Router

I am building an application using twilio's Task Router. I followed the quickstart tutorial at https://www.twilio.com/blog/2015/02/creating-a-priority-queue-for-your-call-centre-with-taskrouter.html.
I am able to get the task created. Assignment callback is also reaching the application. In the assignment callback response, I return the following JSON response,
{
"instruction": "dequeue"
"post_work_activity_sid": "WA157bdc5be67d91999de9fc68bb1d0f67"
}
The dequeue operation is not happening. I have double checked if I have assigned contact_uri for the worker. Still call is not reaching the worker. Menawhile, the portal says the worker is reserved. Eventually the call times out and the task gets marked as canceled.
My question is whether this ocurring because the worker's contact uri is another Twilio phone number I own. When I dial that contact uri , I am able to hear the "Say" response that I had preconfigured.
Does anybody have suggestion here?

Prevent client repeatedly sending requests

I have a spring controller and request mapped method.
#RequestMapping(value = { "/doSomething.do" })
public ModelAndView emailToNonBelievers(){
.....
// do something which takes lot of time
// send response..
return modelAndView;
}
This method takes very long time, about an hour.(It is for Admin, not users. And Admin doesn't need to wait an hour. Just fire and forget, that's ok. And this is not a batch job)
But I found that client send requests repeatedly with 3 minutes interval(observed 6 times and I stopeed Spring service).
I guess because client didn't get any response from server.
If my guess is right, server should response sort of "Your request is accepted, just shut up and wait!!" .
But how to send response(200 ok) before jobs finished in Spring?
Or am I missing something?
In this situation it would be recommended to use asynchronous task processing. Spring comes with out-of-box support for it via #Async annotation.Consult my answer for detailed setup for similar query and here for docs.

How to test that async controller is really running async

I have created simple async controllers that call into async methods that then call PostAsync on the HttpClient to retrieve various REST service endpoints. All works well, but how can I test to insure that the controller is really calling a background thread and releasing the primary thread back to the pool? I want to insure that I do have all the async sweetness working correctly and that I am not inadvertently running synchronous methods despite all my work to make everything async.
I found that System.Threading.Thread.CurrentThread.IsThreadPoolThread will provide whether the current thread is still a threadpool thread or not.

Resources