-
Notifications
You must be signed in to change notification settings - Fork 1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
TestKit ImplicitSender - async await broken #907
Comments
actually, it will leak context even if two or more tests are running and are async, e.g. Now implicit As @nvivo noted on gitter, instead of setting state in a thread static, it could be set in the CallContext. But.. xUnit 1.9.2 blows up if we use CallContext for this.. This would however affect throghput negatively, but I guess correct and slower is better than fast and broken.. |
Even then its definitely not a silver bullet. This guy explains it perfectly: http://blog.stephencleary.com/2013/04/implicit-async-context-asynclocal.html |
cc @StephenCleary we need you! <3 |
My only worry is that these PRs are only treating symptoms, not root causes. The fact is that these problems should not be happening in the first place. This has nothing to do with akka and async being incompatible at some fundamental level, it's just about implementation. If a synccontext wrapper is a solution, this can be applied to any environment, not only xunit. That means ditching CallContext, changing dispatchers a little bit and fixing these problems forever. But the same solution can be achieved by keep using just CallContext and adjusting the ActorTaskScheduler to flow these values in the right order. More issues will appear because of async. We should understand what is causing them first, and mainly have an agreement by the leaders on what the issue is and the direction we should follow to fix them once and for all. I'm afraid keep accepting patches to very specific problems will only turn akka in a patchwork quilt. |
The only problem with a custom SynchronizationContext I see it that somewhere could be |
That particular case has nothing to do with async actors, dispatchers, etc. It's because of the free context in which xunit runs tests. |
This is exactly the short sight I'm talking about. It's all the same problem, this is just treating symptoms. I'm fine with working around a specific issue to keep the project going. But it's different to say this is fixing a real issue. It's not. Just like #905 didn't fix anything, it's all band-aids. |
I totally agree with you @nvivo, but there is more to it. We have to stick with the API we've got for V1+ , OnReceive returns a bool. so we cannot return tasks. and changing that API at this point is a no go. We might have the luxury to change this for v2 or simply make it work differently in Akka.Typed. But right now, we are stuck with the implicit context as that is how JVM Akka is designed and the Receive API looks the way it does. So we need to focus on whats the correct thing to do in the current position. So what is our best alternative right now? |
It can return Task. The dispatcher just has to support asynchronous execution, that's it. |
Our message pipeline is extremely lightweight right now. On my machine it drops from 34 mil messages down to 20 mil messages per sec in the benchmark app, from increased GC pressure alone. This is a prices that all actors have to pay if we make that change, even if they are not async. |
A completed task cached in a static variable costs absolutely nothing. No GC pressure, etc |
I'm not follwoing, when is a completed task a cached static variable? e.g. Or are you saying we should do something like:
where that task is declared somewhere else? |
Another thing that I also don't get is this: Lets say that OnReceive returns When should the TaskScheduler or SynchronizationContext be applied? For every single message? As that needs to be set before OnReceive is invoked. I feel like an Ogre with a peanut brain when discussing this topic as everyone seem to have a very clear idea on how this could be solved while I myself don't :) |
https://github.com/StephenCleary/AsyncEx/wiki/TaskConstants
Before calling
Sync context may be a part of ActorCell and also be reused.
This benchmark takes 00:00:01.2104391 to run on my hardware (windows is running in KVM, but still). ~100 million context switches per second. |
Oh, found a better the place for |
@rogeralsing Please, check how much does performance drop on your hardware with proper benchmarking setup. |
Wasnt the consensus that SynchronizationContext could not be used? as we do not own the threads we run on. |
Please, see implementation.
|
Generally, a custom SyncCtx should be avoided. If it's possible to solve this by using the logical call context (.NET 4.5+ only), I would prefer that route. Or if it's possible to access context values through some other means, that would be even better (but a much more substantial change). SyncCtx is more of a "platform type". UIs have them. ASP.NET vCurrent does have one, but in vNext they are planning to remove it. SignalR explicitly leaves the ASP.NET vCurrent context before executing its user-provided code. These are not conclusive arguments; just points to consider. |
Thanks @StephenCleary! Very good to know about this. |
Can You explain why a custom sync ctx should be avoided? And why they are moving away from these things in vnext? -----Original Message----- Generally, a custom SyncCtx should be avoided. If it's possible to solve this by using the logical call context (.NET 4.5+ only), I would prefer that route. Or if it's possible to access context values through some other means, that would be even better (but a much more substantial change). |
To be honest, I'm not entirely sure. I was a bit surprised that the SignalR team was adamantly opposed to introducing a SyncCtx, since I consider SignalR as more of a "platform" than a "library". On the other hand, xUnit (preview v3) always provides a SyncCtx for their unit tests. But that kind of makes sense, since most code will run in some kind of a SyncCtx at runtime. My gut feelings are:
I think it's for these reasons that there's a general move away from SyncCtx. |
I think we can close the issue for now. Tests have their workaround, reentrancy is removed, ambient context will be removed in Akka.Typed, RunTask/ReceiveActor work fine, God in his heaven, all's right with the world. |
@thomastomanek If I remember correctly, |
Another async await issue incoming..
in the
TestKitBase
, we have this lines:This sets the testActor as the current sender for all tests that are not decorated with
INoImplicitSender
So far so good.
But as test methods can be async, this does not work, for the very same reasons we had to hack the world to get async await to work inside actors.
The implicit context is lost in the
await
and all code running in the test method be incorrect.And worse:
if there are two parallel tests running at the same time, where one has
INoImplicitSender
and one hasnt'Its completely possible that the context set above leaks over to the other test if that happens to inherit the same thread while awaiting.
So now good folks, here we have correct Task based methods, with broken async await support.
As these tests do return tasks, if I get what everyone else is saying here, it should be an easy fix?
(In my head it's not, I still think the implicit actor context needs to async flow in the tests also.
But I've been wrong before on this topic :-) )
cc @nvivo @kekekeks @Danthar @HCanber
Someone reported this in a PR recently, that the context had leaked over to another test.
And had to set
.Current = null
So, shoot, anyone have any ideas how to fix this?
The text was updated successfully, but these errors were encountered: