Why doesn't the SynchronizationContext flow here? - async-await

In my Asp.Net WebApi controller (framework version 4.6.1) I have the following code:
[Route("async_test_2")]
public async Task<IHttpActionResult> AsyncTest2()
{
TelemetryDebugWriter.IsTracingDisabled = true;
var aspNetContext = SynchronizationContext.Current;
SynchronizationContext.SetSynchronizationContext(new SynchronizationContext()); //set context while calling AsyncMethod
var task = AsyncMethod();
SynchronizationContext.SetSynchronizationContext(aspNetContext); //Restore AspNet context before awaiting
DebugContext("Before outer await");
await Task.WhenAll(new Task[] { task });
DebugContext("After outer await");
return Ok();
}
private async Task AsyncMethod()
{
DebugContext("Before inner await");
await Task.Delay(2000);
DebugContext("After inner await");
}
private void DebugContext(string location)
{
System.Diagnostics.Debug.WriteLine(location + " --- SyncContext: " + (SynchronizationContext.Current?.ToString() ?? "null") + "; ManagedThreadId: " + Thread.CurrentThread.ManagedThreadId);
}
The debug output is:
Before inner await --- SyncContext: System.Threading.SynchronizationContext; ManagedThreadId: 6
Before outer await --- SyncContext: System.Web.AspNetSynchronizationContext; ManagedThreadId: 6
After inner await --- SyncContext: null; ManagedThreadId: 5
After outer await --- SyncContext: System.Web.AspNetSynchronizationContext; ManagedThreadId: 6
Why would the continuation 'After inner await' have a null SynchronizationContext? If I simply remove the call to SetSynchronizationContext and the call to restore it (i.e. don't modify the context, leaving the default AspNetSynchronizationContext), then the context is not null in any debug output.
Before inner await --- SyncContext: System.Web.AspNetSynchronizationContext; ManagedThreadId: 7
Before outer await --- SyncContext: System.Web.AspNetSynchronizationContext; ManagedThreadId: 7
After inner await --- SyncContext: System.Web.AspNetSynchronizationContext; ManagedThreadId: 8
After outer await --- SyncContext: System.Web.AspNetSynchronizationContext; ManagedThreadId: 8
Adding 'ConfigureAwait(false)' after the inner await will cause the context to be null in the continuation as expected.
Before inner await --- SyncContext: System.Web.AspNetSynchronizationContext; ManagedThreadId: 7
Before outer await --- SyncContext: System.Web.AspNetSynchronizationContext; ManagedThreadId: 7
After inner await --- SyncContext: null; ManagedThreadId: 7
After outer await --- SyncContext: System.Web.AspNetSynchronizationContext; ManagedThreadId: 8
So it works as expected when the AspNetSynchronizationContext is active, but not when a default SynchronizationContext is active. In that case, it's always null in the continuation regardless of whether ConfigureAwait(false) is called.

Recently, I begin to learn something about SynchronizationContext, after read .Net Framewrok source code, I find that await just capture the current SynchronizationContext and Post the remain code exectution to the context, but it does not set the SynchronizaitonContext, so you got a null.
The AspNetSynchronizationContext does some extra work to ensure that even tasks are executed in different threads, the SynchronizationContext.Current are same. You can check the ISyncContext.Enter implementaion:
// set synchronization context for the current thread to support the async pattern
_originalSynchronizationContext = AsyncOperationManager.SynchronizationContext;
AspNetSynchronizationContextBase aspNetSynchronizationContext = HttpContext.SyncContext;
AsyncOperationManager.SynchronizationContext = aspNetSynchronizationContext;
the AsyncOperationManger.SynchronizationContext is just call SynchronizationContext.SetSynchronizationContext method to set SynchronizationContext.Current
You can check out this simple implementation of SynchronizationContext to replace
new SynchronizationContext()
with
new CustomSyncContext()
CustomSyncContext:
public class CustomSyncContext : SynchronizationContext
{
private Task lastTask = Task.FromResult<object>(null);
private object lockObj = new object();
public override void Post(SendOrPostCallback d, object state)
{
Debug.WriteLine("post back from await");
lock (lockObj)
{
var newTask = lastTask.ContinueWith(_=>{
AsyncOperationManager.SynchronizationContext = this;
d(state);
}, TaskScheduler.Default);
lastTask = newTask;
}
}
public override SynchronizationContext CreateCopy()
{
return this;
}
}
and find out that SynchronizationContext.Current is not null any more

SynchronizationContext.Current is thread local. Task.Delay runs on a new thread (the myth that Tasks automagically "eliminate threads" is dangerous), therefore its SynchronizationContext is null. All threads in a thread pool get null (it's unsafe to carry a real object there - they never die, you'd need very careful cleanup code after every run or you are having unholy entanglement).
That null means that continuation records are sent to the thread pool's principal tread which serializes them (in a queue) but will not run them. He's a lazy bastard :-) who delegates everything he can. Instead he will send these continuation records back into his own thread pool when their time to run comes - and won't guarantee execution order at all (that serializing was just for his own safety and is a hot spot). So, at the time your "After inner await" debug print is running, SynchronizationContext is again null and you are in unknown thread.
You'd have to write your own SynchronizationContext derivative and manage it's instances (without locking). You could assign them to thread pool's threads but you'd have to be very careful and detect when the last continuation from a chain is finished since at that point you have to clean up. You'd essentially need your own derivative of the thread class as well.
Don't forget that threads in a thread pool live forever - the whole purpose of the thread pool is to never have to destroy and latter create new thread objects. Plus GC treats all thread objects as roots which means that whatever they touch becomes eternal as well (some people would call that leaking) unless you explicitly nullify pointers.

Related

Weird Behavior while missing an await keyword generates error: Cannot access a disposed context instance

I recently ran into this error. I have never came across this before so wondering!
Cannot access a disposed context instance. A common cause of this error is disposing a context instance that was resolved from dependency injection and then later trying to use the same context instance elsewhere in your application. This may occur if you are calling 'Dispose' on the context instance, or wrapping it in a using statement. If you are using dependency injection, you should let the dependency injection container take care of disposing context instances.
Object name: 'OrderDbContext'.
The only thing i missed which produced this error is the await keyword in the controller action method before _mediator.Send(checkoutCommand); Once I added the await keyword this error vanished.
What (the heck) is wrong with missing this await keyword? The error does not explicitly state that. Can someone explain why missing an await keyword cause an error that database context is disposed?
Controller Action:
public async Task<IActionResult> Checkout(CheckoutOrderCommand checkoutCommand)
{
**var id = _mediator.Send(checkoutCommand);**
return CreatedAtRoute("Get Order by Id", id);
}
CQRS Mediatr Instructions
public class CheckoutOrderCommandHandler : IRequestHandler<CheckoutOrderCommand, int>
{
private readonly IOrderUow _orderUow;
private readonly IMapper _mapper;
public CheckoutOrderCommandHandler(IOrderUow orderUow,
IMapper mapper)
{
_orderUow = orderUow;
_mapper = mapper;
}
public async Task<int> Handle(CheckoutOrderCommand request, CancellationToken cancellationToken)
{
var order = _mapper.Map<Order>(request);
// Populate base entity fields
order.CreatedBy = Constants.CurrentUser;
// create new order
var newOrder = await _orderUow.AddOrderAsync(order);
return newOrder.Id;
}
}
Unit of work implementation
public class OrderUow : IOrderUow
{
private readonly OrderDbContext _orderContext;
public OrderUow(OrderDbContext orderContext)
{
_orderContext = orderContext;
}
public async Task<Order> AddOrderAsync(Order order)
{
try
{
await _orderContext.Orders.AddAsync(order);
await _orderContext.SaveChangesAsync();
}
catch (Exception ex)
{
}
return order;
}
}
Missing an await without explicitly handling the task that is returned will mean that the code calling the asynchronous method will not create a resumption point and instead will continue executing to completion, in your case leading to the disposal of the DbContext.
Asyncrhronous code is multi-threaded behind the scenes. Think of it this way, your web request enters on Thread #1 which creates a DbContext instance via an IoC container, calls an asynchronous method, then returns. When the code calls an async method, it automatically hands that code off to a worker thread to execute. By adding await you tell .Net to create a resume point to come back to. That may be the original calling thread, or a new worker thread, though the important thing is that the calling code will resume only after the async method completes. Without await, there is no resume point, so the calling code continues after the async method call. This can lead to all kinds of bad behaviour. The calling code can end up completing and disposing the DbContext (what you are seeing) or if it calls another operation against the DbContext you could end up with an exception complaining about access across multiple threads since a DbContext detects that and does not allow access across threads.
You can observe the threading behaviour by inspecting Thread.CurrentThread.ManagedThreadId before the async method call, inside the async method, then after the async method call.
Without the await you would see Thread #X before the method call, then Thread #Y inside the async method, then back to Thread #X after. While debugging it would most likely appear to work since the worker thread would likely finish by the time you were done with the breakpoints, but at runtime that worker thread (Y) would have been started, but the code after the call on thread X would continue running, ultimately disposing of your DbContext likely before Thread Y was finished executing. With the await call, you would likely see Thread #X before the method call, Thread #Y inside, then Thread #Z after the call. The breakpoint after the async call would only be triggered after the async method completes. Thread #X would be released while waiting for the async method, but the DbContext etc. wouldn't be disposed until the resumption point created by awaiting the async method had run. It is possible that the code can resume on the original thread (X) if that thread is available in the pool.
This is a very good reason to follow the general naming convention for asynchronous methods to use the "Async" suffix for the method name. If your Mediator.Send method is async, consider naming it "SendAsync" to make missing await statements a lot more obvious. Also check those compiler warnings! If your project has a lot of warnings that are being ignored, this is a good reason to go through and clean them up so new warnings like this can be spotted quickly and fixed. This is one of the first things I do when starting with a new client is look at how many warnings the team has been ignoring and pointing out some of the nasty ones they weren't aware were lurking in the code base hidden by the noise.

Spring reactive reading web client response

I am in the process of learning about Spring Reactive and have the following basic reactive demo code.
import org.springframework.web.reactive.function.client.WebClient;
// other imports etc
#Slf4j
class WebClientTests {
private static String baseUrl = "http://localhost:8080";
private static WebClient client = WebClient.create(baseUrl);
#Test
void testWebClient() {
Instant start = Instant.now();
Flux.just(1,2,3)
.map(i -> client.get().uri("/person/{id}", i).retrieve().bodyToFlux(Person.class))
.subscribe(s -> {
log.info("subscribed: {}", s);
});
log.info("Elapsed time: " + Duration.between(start, Instant.now()).toMillis() + "ms");
}
}
It outputs the following.
20:32:55.251 [main] DEBUG io.netty.util.ResourceLeakDetector - -Dio.netty.leakDetection.targetRecords: 4
20:32:55.652 [main] INFO com.example.reactive.reactivedemo.WebClientTests - subscribed: MonoFlatMap
20:32:55.652 [main] INFO com.example.reactive.reactivedemo.WebClientTests - subscribed: MonoFlatMap
20:32:55.652 [main] INFO com.example.reactive.reactivedemo.WebClientTests - subscribed: MonoFlatMap
20:32:55.668 [main] INFO com.example.reactive.reactivedemo.WebClientTests - Elapsed time: 84ms
However I am unsure why its not outputting the value of the get request? Its not actually triggering the endpoint.
You almost certainly want to use flatMap(), not map() on your .map(i -> client.get().uri... line.
map() is used for synchronous transformations, where you're returning the actual value you want to map to. You're not returning an actual value - you're returning a publisher from your map method, so that publisher is just returned as is - it's never subscribed to, and since nothing happens until you subscribe, your web request never executes.
flatMap() is used for non-blocking transformations where you return a publisher that emits the value, or values, you want to map to. That publisher is subscribed to as part of your reactive chain, and the value emitted by that publisher passed down the chain to the next operator.

NetworkStream ReadAsync and WriteAsync hang infinitelly when using CancellationTokenSource - Deadlock Caused by Task.Result (or Task.Wait)

After reading pretty much every question on Stack Overflow and Microsoft's documentation about NetworkStream, I dont understand what is wrong with my code.
The problem I see is that my method GetDataAsync() hangs very often. I call this method from Init Method like so:
public MyView(string id)
{
InitializeComponent();
MyViewModel myViewModel = session.Resolve<MyViewModel>(); //Autofac
myiewModel.Init(id);
BindingContext = myViewModel;
}
Above, my View does its initialization, then resolves MyViewModel from Autofac DiC and then calls MyViewModel Init() method to do some additional setup on the VM.
The Init method then calls my Async method GetDataAsync which return a IList like so:
public void Init()
{
// call this Async method to populate a ListView
foreach (var model in GetDataAsync("111").Result)
{
// The List<MyModel> returned by the GetDataAsync is then
// used to load ListView's ObservableCollection<MyModel>
// This ObservableCollection is data-bound to a ListView in
// this View. So, the ListView shows its data once the View
// displays.
}
}
, and here is my GetDataAsync() method including my comments:
public override async Task<IList<MyModel>> GetDataAsync(string id)
{
var timeout = TimeSpan.FromSeconds(20);
try
{
byte[] messageBytes = GetMessageBytes(Id);
using (var cts = new CancellationTokenSource(timeout))
using (TcpClient client = new TcpClient(Ip, Port))
using (NetworkStream stream = client.GetStream())
{
await stream.WriteAsync(messageBytes, 0, messageBytes.Length, cts.Token);
await stream.FlushAsync(cts.Token);
byte[] buffer = new byte[1024];
StringBuilder builder = new StringBuilder();
int bytesRead = 0;
await Task.Delay(500);
while (stream.DataAvailable) // need to Delay to wait for data to be available
{
bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length, cts.Token);
builder.AppendFormat("{0}", Encoding.ASCII.GetString(buffer, 0, bytesRead));
}
string msg = buffer.ToString();
}
return ParseMessageIntoList(msg); // parses message into IList<MyModel>
}
catch (OperationCanceledException oce)
{
return await Task.FromResult<IList<RoomGuestModel>>(new List<RoomGuestModel>());
}
catch (Exception ex)
{
return await Task.FromResult<IList<RoomGuestModel>>(new List<RoomGuestModel>());
}
}
I would expect that a ReadAsync or WriteAsync either complete successfully, throw some exception, or get cancelled after 10 seconds in which case I would catch OperationCanceledException.
However, it just hangs endlessly when I call method above. If I am debugging and have some breakpoints in the code above, I will be able to go through the method entirely but if I call it 2nd time, app just hangs forever.
I am new to Tasks and Async programming, so I am also not sure I do my cancellations and exception handling properly here?
UPDATE AND FIX
I figured out how to fix the deadlock issue. In hope this will help others sho might run into the same issue, I'll first explain it. The articles that helped me a lot are:
https://devblogs.microsoft.com/pfxteam/await-and-ui-and-deadlocks-oh-my/ by Stephen Taub
https://montemagno.com/c-sharp-developers-stop-calling-dot-result/ by James Montemagno
https://msdn.microsoft.com/en-us/magazine/jj991977.aspx by StephenCleary
https://blog.xamarin.com/getting-started-with-async-await/ by Jon Goldberger
#StephenCleary was great help understanding the issue. Calling Result or Wait (above, I call Result when calling GetDataAsync) will lead to dead-lock.
The context thread (UI in this case) is now waiting for GetDataAsync to complete, but GetDataAsync captures the current context-thread (UI thread), so it can resume on it once it gets data from TCP. But since this context-thread is now blocked by call to Result, it cannot resume.
The end result is that it looks like call to GetDataAsync has deadlocked but in reality, it is call to Result that deadlocked.
After reading tons of articles from #StephenTaub, #StephenCleary, #JamesMontemagno, #JoeGoldenberger (thank you all), I started getting understanding of the issue (I am new to TAP/async/await).
Then I discovered continuations in Tasks and how to use them to resolve the issue (thanks to Stephen Taub's article above).
So, instead of calling it like:
IList<MyModel> models = GetDataAsync("111").Result;
foeach(var model in models)
{
MyModelsObservableCollection.Add(model);
}
, I call it with continuation like this:
GetDataAsync(id)
.ContinueWith((antecedant) =>
{
foreach(var model in antecedant.Result)
{
MyModelsObservableCollection.Add(model);
}
}, TaskContinuationOptions.OnlyOnRanToCompletion)
.ContinueWith((antecedant) =>
{
var error = antecedant.Exception.Flatten();
}, TaskContinuationOptions.OnlyOnFaulted);
This seam to have fixed my deadlocking issue and now my list will load fine even though it is loaded from the constructor.
So, this seam to work just fine. But #JoeGoldenberger also suggests another solution in his article https://blog.xamarin.com/getting-started-with-async-await/ which is to use Task.Run(async()=>{...}); and inside that await GetDataAsync and load ObservableCollection. So, I gave that a try as well and that is not blocking either, so working great:
Task.Run(async() =>
{
IList<MyModel> models = await GetDataAsync(id);
foreach (var model in models)
{
MyModelsObservableCollection.Add(model);
}
});
So, it looks like either of these 2 will remove deadlock just fine. And since above my Init method is called from a c-tor; therefore, I cannot make it Async and await on this, using one of the 2 methods described above resolves my problem. I dont know which one is better but in my tests, they do work.
Your problem is most likely due to GetDataAsync("111").Result. You shouldn't block on async code.
This can cause deadocks. E.g., if you're on a UI thread, the UI thread will start GetDataAsync and run it until it hits an await. At this point, GetDataAsync returns an incomplete task, and the .Result call blocks the UI thread until that task is completed.
Eventually, the inner async call completes and GetDataAsync is ready to resume executing after its await. By default, await captures its context and resumes on that context. Which in this example is the UI thread. Which is blocked since it called Result. So, the UI thread is waiting for GetDataAsync to complete, and GetDataAsync is waiting for the UI thread so it can complete: deadlock.
The proper solution is to go async all the way; replace .Result with await, and make the necessary changes to other code for that to happen.
As stated in my update, going async all the way by providing an async lambda like below resolved the issue for me
Task.Run(async() =>
{
IList<MyModel> models = await GetDataAsync(id);
foreach (var model in models)
{
MyModelsObservableCollection.Add(model);
}
});
Loading asynchronously an observable collection in a ctor this way (in my case, ctor calls Init which then uses this Task.Run) solves problem

await async code seems to still be running sync

I'm new to async / await, and have been trying to implement it in my 4.6 web api 2 project.
public class MyController : ApiController
{
public async Task<Thing> Search(String searchTerms)
{
myThing = new Thing();
myThing.FirstProperty = await doFirstPropertyAsync(searchTerms);
myThing.SecondProperty = await doSecondPropertyAsync(searchTerms);
return myThing;
}
}
Basically I'm returning a class (Thing) that has two properties that take a few seconds each to populate. I'm actually loading maybe ~10 properties, but it's the same logic for all of them.
public async Task<MyCoolSubObject> doFirstPropertyAsync(string searchTerms)
{
SomeController sController = new SomeController();
Debug.WriteLine("first - starting.");
var x = await Task.Run(()=>sController.Lookup(searchTerms));
Debug.WriteLine("first - finishing.");
return x;
}
public async Task<MyCoolSubObject> doSecondPropertyAsync(string searchTerms)
{
SomeOtherController sController = new SomeOtherController();
Debug.WriteLine("second - starting.");
var x = await Task.Run(()=>sController.Lookup(searchTerms));
Debug.WriteLine("second - finishing.");
return x;
}
What's got my scratching my head:
When I look at the debug outputs, the first property assignment method call starts and finishes before the second completes. Again, I actually have like ten of these and no matter what order I put the property assignments in they complete in a serial fashion (ie: nothing starts until another one finishes).
These property assignments under the hood are basically doing database calls that take a while, hence I wanted them running in parallel if possible. The methods themselves ( SomeController.Lookup(string) ) contain no await/async/task stuff.
Again, I actually have like ten of these and no matter what order I
put the property assignments in they complete in a serial fashion (ie:
nothing starts until another one finishes).
This happens because in your code you use the await keyword as soon as you kickoff the task, by doing that you prevent the method to continue to execute the next statement before the task will be done.
If you want to run your tasks in parallel you should kickoff all of them and only then await all of them using Task.WhenAll:
public async Task<Thing> Search(String searchTerms)
{
myThing = new Thing();
var firstTask = doFirstPropertyAsync(searchTerms);
var secondTask = doSecondPropertyAsync(searchTerms);
await Task.WhenAll(firstTask, secondTask);
myThing.FirstProperty = await firstTask;
myThing.SecondProperty = await secondTask;
return myThing;
}
Note that when we await every task separately after we await Task.WhenAll the tasks have already been done, we do that in order to get the result from the task, although we can use the Result property (it will not block since we know the task has already been done) I prefer to use await for consistency reasons.

Android using AsyncTask to update the UI

I want to know when the asynctask is finished, such that I could update the UI.
Can anybody help???? thanks!!!
public String[] getinfo(int id) {
String[] QueueNo = null;
try {
new DLfromServer().execute("url link"); // this is the asynctask
// want to do stuff here after the asynctask is completed
// actually I want to return a string result after the task is finished....
}
} catch (JSONException e) {
Log.e("GetJSON", "Err:", e);
}
return QueueNo;
}
want to know when the asynctask is finished, such that I could update
the UI.
Yes, you can use onPostExecute method which call on UI Thread after doInBackground execution is completed.
if you want to get data back on Main UI Thread then use AsyncTask.get() method for executing AsyncTask because this method make wait on UI Thread until doInBackground execution is completed .
String str_result= new DLfromServer().execute("url link").get();
// now use str_result for Updating result
NOTE :- you will need to call AsyncTask.get() inside an Thread instead of Main UI Thread otherwise calling of get() method will freeze Main Thread until doInBackground execution is complete

Resources