Async Await with Task.Run method for DB call - c#

We have an async/await method GetLoanDataAsync which calls a stored procedurre through entity framework which is being called by a sync method GetData.
GetLoanData takes a good amount of time to execute and probably that was the reason that we wrote as async/await which can be used by multiple places.
I understand that we shouldn't mix async and sync calls but let's say if we have this scenario and we are using Task.Run() to call async method GetLoanDataAsync from sync method GetData which I understand that method - GetLoanDataAsync will run on a background thread.
My question is that what if we had a sync version of async method GetLoanDataAsync and called using Task.Run() from GetData than what difference it would make in this case?
Providing more details regarding the issue-
We have ASP.NET REST Web API which return type is not a Task. This is called from angular app. This api has few methods called GetData() and where we wait for the result from GetLoanDataAsync. As per my understanding GetLoanDataAsync will be called in background thread and will be able to execute GetUserDetails(), once this finish it will give back the result from executed GetLoanDataAsync.
Code -
public List<int> GetData(int id)
{
// Calls GetLoanDataAsync
var result = Task.Run(()=> GetLoanDataAsync(id));
// calls couple other sync methods
GetUserDetails();
return result.GetAwaiter().GetResult();
}
GetLoanDataAsync().Result will result in deadlock which was the earlier issue. To fix this we are temporarily trying to use Task.Run till we make overall api as an async.

If you compare a sync vs async version, then the most obvious difference is that the sync version is tying up a thread for the duration of the DB call, which seems unnecessary if all the work is at the database. Whether this is a problem depends on your throughput.
By using Task.Run, you're allowing that operation to run in parallel with other work. This is fine, as long as you don't have any touch-points that impact thread-safety, or which depend on a single logical execution flow.
If you want to use async effectively, it is best to consider it "sticky" - i.e. if X is async, then everything that calls X (directly or indirectly) needs to be async.

Related

How does async prevent errors caused due to parallel execution?

How does using await make code thread safe?
Link: https://learn.microsoft.com/en-us/ef/core/dbcontext-configuration/#avoiding-dbcontext-threading-issues
Entity Framework Core does not support multiple parallel operations
being run on the same DbContext instance. This includes both parallel
execution of async queries and any explicit concurrent use from
multiple threads. Therefore, always await async calls immediately, or
use separate DbContext instances for operations that execute in
parallel.
Say 1 db call is in progress and thread 1 is on it. While it's working in it;
Case 1:
Assume I am not using async. A parallel call is made by another thread, hence there will be clash and error.
Case 2:
Assume I use async. A parallel call is made by another thread:
Case 2.a: since we use async, when 1st thread makes the request, and waiting for response, it will release the thread so thread 2 won't clash when making the request. I get this point.
Case 2.b what if both threads really make request at the same time.
Is case 2.b possible and does using async be of any help here?
"always await async calls immediately" means to avoid starting multiple async operations and waiting for them to finish later (as one would do for multiple HTTP requests).
Here is typical example of what one should do for async HTTP calls but invalid for EF operations:
// start operations early so results are there after our CPU intensive code complete
var task1 = dbContext.GetSomething();
var task2 = dbContext.GetMore();
// do something slow here to let both operations to finish
var result1 = await task1;
// even more code
var result2 = await task2;
This code will let both operations to run in parallel thus potentially causing issues with dbContext.
The guidance recommends:
var result1 = await dbContext.GetSomething();
var result2 = await dbContext.GetMore();
// run slow code now sequntially to avoid parallel calls to dbContext.
Indeed if you are careful you can do similar interleaving of calls on DBContext and other operations on unrelated objects - i.e. HTTP call and DBContext call in parallel, or DBContext call and CPU-intensive code to run in parallel with late awiat of EF call.
Note that the guidance can't help much with sharing context between two threads - as with any non-thread-safe object it is your responsibility to prevent simultaneous access to such shared objects.
The thing you're missing is that in the common case of ASP.NET Core, the DbContext is scoped to the HTTP request, and the framework guarantees that there will be only one middleware or controller method running for a request at any one time. So awaiting the async calls is sufficient to prevent parallel DbContext access.

Calling async method from sync method is ASP .NET web api - issue

I have a ASP .NET web api 2 application, and I'm trying to call asnyc method from sync method and meanwhile I encountered some issues. If I just call the method as a regular method the body after delay doesn't get executed, if I call it with Task.Run() it gets executed
public void CallingMethod(MethodExecutionArgs args)
{
//do something with the args
System.Diagnostics.Debug.WriteLine("BEFORE ");
WriteFileToDiskAsync(args); // If I run only this, I never see "WriteFile() - AFTER delay" in the output
Task.Run(async () => await WriteFileToDiskAsync(args)); // this executes the entire async method
System.Diagnostics.Debug.WriteLine($"Finally written from sync method");
}
private async Task<bool> WriteFileToDiskAsync(dynamic file)
{
System.Diagnostics.Debug.WriteLine("Before delay inside async");
await Task.Delay(3000);
System.Diagnostics.Debug.WriteLine("WriteFile() - AFTER delay");
}
Result: I always see the lines written from CallingMethod, but when I call the async method like a regular method, I only see the "Before delay inside async", If I call it with Task.Run() it see both lines from the async method.
Question1: Can someone explain this behavior, why doesn't the async method execute fully?
Does it have something to do with what Stephen Cleary says: If you lose your AppDomain for any reason, that in-progress work is lost.
I read these articles but can't figure out why is this happening:
How to call asynchronous method from synchronous method in C#?
Fire and forget async method in asp.net mvc
C# async/await with/without awaiting (fire and forget)
https://blog.stephencleary.com/2012/12/returning-early-from-aspnet-requests.html According to most articles what I'm trying to do is not recommended (among other things the exceptions from the async method would get swallowed) but in my case I already have the information that I need to generate the response and what is done in the Async method doesn't concern the client at all...
Context: What I'm trying to achieve is, on a existing API route that creates a X Resource (saves it in a database), after the X resource is created, I want to asynchronously call a method that will Create a json file with some information from that X Resource and save it in a filesystem. But even if the writing of the file fails, I want to return a successful response to the client (because his request was to actually save the X Resource - which succeeded) he doesn't care about Creating external file in XYZ filesystem.
Question2: What would you say is the best practice to achieve what I described above, considering all the existing methods chained in the CreateResource route are sync?
Question1: Can someone explain this behavior, why doesn't the async method execute fully? Does it have something to do with what Stephen Cleary says: If you lose your AppDomain for any reason, that in-progress work is lost.
No. The AppDomain is still there in this case. In ASP.NET (pre-Core), there is an ASP.NET SynchronizationContext that represents the request. await by default captures the current context and uses that to resume executing its async method.
So, when the await completes, it attempts to resume executing on the SynchronizationContext for that request. However, that request has been completed, and so it doesn't make sense to resume on that context. The resulting behavior is undefined.
Question2: What would you say is the best practice to achieve what I described above, considering all the existing methods chained in the CreateResource route are sync?
If you are sure you want to return early, then you should have a background service handle creating the file, not the ASP.NET service. Since you have a database already, you could use the Outbox Pattern, where you place messages in an "outbox" table as part of the same transaction as your resource creation. Then a separate background service reads the "outbox" table and writes the JSON file.

If I'm going to use the result from await immediately, do I get any benefit from async?

Consider the code in this example:
https://learn.microsoft.com/en-us/aspnet/web-api/overview/advanced/calling-a-web-api-from-a-net-client
In several places they have code that looks like this:
if (response.IsSuccessStatusCode)
{
product = await response.Content.ReadAsAsync<Product>();
}
return product;
The way I see it, if there is no independent code following the await, then there is little benefit to using async. (I know that there are many API's that are *AsAsync() only, so in those cases I don't have a choice.)
Or am I missing something? Is there a benefit for going all async, all the time?
Yes there is benefit as we are not blocking caller on the operation that we are doing which is not the case for sync calls.
Think of it was called in windows form application as synchrounous call then on a button click suppose, then the app would be unresponsive and user wouldn't be able to do any operation until the call to Web API method complete s either with success or failure which we don't want nowadays in many cases I.e keep the application responsive for better UX.
The basic purpose is to simplify the old way of using background worker class to do long running operations or I/O bound operations. The asynchronous execution will cause not to block the caller code and resume from where it left when the result is returned back from the operation.
So in the above case calling a Web API method involves network latency and it could take more than normal time and if we are not calling it asynchronously we have blocked the calling code or thread until the result is returned.
Update:
To clarify Calling async method without await wouldnt block but your control would flow through and you won't be able to access the result while await would keep that context, without await you will have to wait for it to complete and block it like Async().Result which ofcoruse means calling async method synchronously.
Hope it helps

Can't call async method synchronously from MeasureOverride

I need to call an async method from MeasureOverride. This call should be synchronous because I need to return the value of the async method.
I tried about a dozen different calls from these threads:
Synchronously waiting for an async operation, and why does Wait() freeze the program here
How would I run an async Task<T> method synchronously?
They all failed, some wouldn't compile in Universal Windows Applications, some weren't synchronous, some provoked a deadlock etc..
I feel strongly against async/await because of how it contaminates the call hierarchy prototypes. At the override level I'm stuck with no async keyword and I need to call await synchronously from the blackbox. Concretely how should I go about it?
The first thing you should do is take a step back. There should be no need to call asynchronous code from within a MeasureOverride in the first place.
Asynchronous code generally implies I/O-bound operations. And a XAML UI element that needs to send a request to a remote web server, query a database, or read a file, just to know what its size is, is doing it wrong. That's a fast track to app certification rejection.
The best solution is almost certainly to move the asynchronous code out of the element itself. Only create/modify the UI elements after the necessary asynchronous work completes.
That said, if you feel you must block the UI thread while asynchronous operations complete, I've compiled a list of every hack I know of, published in my MSDN article on brownfield asynchronous development.

async datareader and the order of execution

I am using Web API. I know I have to use a full async stack to get its benefits. That means the API Controller are async calls to my service and my service does async calls to my dataprovider which do async datareader for example.
I guess when I start with using async in the controller I also should do an OpenAsync() on a database connection and use only the async Non-/Query calls.
Is this true?
When I have 3 NonQueries (A) doing stuff on Table 1,2,3. When this task is finished there MUST follow 4 NonQueries (B) doing stuff on Table 1,2,3.
Can I make use of the ExecuteNonQueryAsync method for A OR do I have to fear that B will be faster executed than A which might cause inconsistent data in my case?
You don't have to use only async methods, but I recommend you mostly do when there's an async option. But make sure those operations are truly async.
If you await all your async calls than the order will be the same as if you didn't use async.
There's a difference between parallel and async. An async flow isn't necessarily a parallel one.
1) False, not necessarily
2) Doesn't apply then.
By marking your actions async the apppool thread will be released for new requests and the current request is handled by a background thread.

Categories