-
Notifications
You must be signed in to change notification settings - Fork 1.5k
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
PreserveAsyncOrder=false with async message handler can cause thread pool exhaustion & extremely bad performance #759
Comments
What is the default value for PreserveAsyncOrder? Does it default to true or false? |
Should be false if you don't care about message ordering (performance) I'm not sure I think it's true by default |
I'm afraid that id you're using |
I've just updated to 1.2.6 and it looks like the default is 'true', although the latest source code default to false. @niemyjski do you performance improvement when set to false or still encounter performance degradation? |
PreserveAsyncOrder = true makes Assert.ThrowsAsync code hang for me. Environment: .netcore 2.1
If in my "someController" I use SE Redis with PreserveAsyncOrder = true. It deadlocks. This is similar to this issue: |
Yes, I see degradation in both cases, but this shows what happens in real world apps. We really need an async on message handler as real life work loads use this to do things like invalidate cache and the like. I had to build a task queue to fix this issue. |
@niemyjski do you have an example of the task queue that you can share? |
Since I set it to false I see thread pool exhaustion as reported here. Setting it back to true resolved the issue |
FYI I intend to look at this in the 2.0 work; we already have a bespoke pool there... Amaya as well put it to good use! |
Note: if you're using TLS (cloud hosts, usually) or "not .NET framework on
Windows", then it is also possible that the main cause here is the IO code
strategy. This has been *completely rewritten* for 2.0. I'd be very
interested to know whether the above two options apply to people suffering
from this. Meaning: are you using TLS or "not .NET on Windows"?
…On Wed, 4 Jul 2018, 20:12 Yoni Shalom, ***@***.***> wrote:
Since I set it to false I see thread pool exhaustion as reported here.
Setting it back to true resolved the issue
—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
<#759 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AABDsFEx8fNv0FdAMynnuJO8bqW8vDQ6ks5uDROTgaJpZM4RI8vH>
.
|
There is a new API in 2.0 which provides everything you'd want here for the ordered scenario (in old terms: I'm interested in the use-case for unordered here. We have options. It sounds like you want to use async handlers, which suggests we're waiting for them in some way; does that mean we're actually talking about something like max concurrency? or...? For example, are you looking for something like:
? Because: this type of thing would actually be possible for us to add now, in the 2.0 code. If you don't care about max concurrency, then... frankly, make your existing handler |
I'm going to go ahead and assume that the 2.0 changes essentially "fix" this; it completely isolates the main pump from the completion queue, and has a separate API for ordered queues (PreserveAsyncOrder just isn't a thing any more, except as a dummy prop with a |
Thanks, I'll test this out once 2.0 becomes available :) |
Also yes, I want to handle them asyncly in my message bus / pub sub and I don't really care about order just that my thread pool doesn't blow up. |
See, that's a fun problem; it is easy for us to restrict you to just a limited pool, but: it is absurdly easy for async/await to end up stealing threads, usually with the effect that asp.net (or whatever) slowly does a takeover; if we hard limit you, then, you can get to the point where there is no pool thread left to service you. What we do instead is use a custom pool which tries to keep everything local, but if a backlog starts to appear, it kicks into the regular thread-pool, so there's always a backup. This does mean that in super high usage you can saturate the pool, but: if you're producing work much faster than you're processing it, that's always going to be a problem - something is going to break somewhere - and if you don't go "boom" with the threads, you'll eventually go "boom" with memory instead, when you've filled up all the available space with pending work. At some point, the only reasonable comment is "process your stuff faster, or add more worker nodes to drain it as a queue in parallel" |
@mgravell with 2.0 is there going to be an async OnMessage? |
@niemyjski are you talking about the handler in the var channel = conn.Subscribe("foo");
while (true)
{
var msg = await channel.ReadAsync();
// do something with msg, perhaps async
} Alternatively, you could kick off an async operation in the existing |
Yeah, I wish the SubscribeAsync allowed you to execute a task and await it (out of order or in order) |
But in the out-of-order case the question becomes: what is awaiting it? Why is awaiting it? What would it so after it has completed? The only useful thing the code could do would be to catch and discard an exception, so... How would it help? Basically the new V2 API plugs this hole for in-order. For out-of-order, I have yet to see an explanation of how this would help. I'm all ears if someone can talk me through it. |
Say, I get a message and now I want to invalidate cache or quickly call an external service. How do I do that async? It becomes an issue in that scenario that we solved with a task queue.. But most of the time it's just something really simple async call. |
You just, from your handler, call a method that is "async Task", with
whatever parameters you need, and either discard the returned object (if
you are confident it will never throw), or use a continuation that observes
errors (if it could conceivably throw).
…On Fri, 7 Sep 2018, 21:23 Blake Niemyjski, ***@***.***> wrote:
Say, I get a message and now I want to invalidate cache or quickly call an
external service. How do I do that async? It becomes an issue in that
scenario that we solved with a task queue.. But most of the time it's just
something really simple async call.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#759 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AABDsKD7G3L0upoXs87tX6hx5LE2dvOPks5uYtW8gaJpZM4RI8vH>
.
|
I'm running the following code on .net core 2.0. When
PreserveAsyncOrder = false
is false and if the message handler containing any async code (Cache invalidation etc, change notifications that send messages over web sockets....) can cause major performance issues as well as thread pool exhaustion as the following code shows... When you change it to true, there are no extra threads and the same code runs in a fraction of the time..Other notes..
We saw this occurring in multiple applications that use Foundatio message bus (https://github.com/FoundatioFx/Foundatio.Redis). We previously had
async void
which is really really bad (dotnet/roslyn#13897). Once we switched it a single GetAwaiter().GetResult() we noticed that the thread pool would become exhausted and our asp.net core app would fall over with a 502.5/503 errors. We are working on moving all this async code into a TaskQueue but that brings in it's own problems (back pressure, unbounded queues etc..., message ordering..).With PreserveAsyncOrder=false
With PreserveAsyncOrder=true
The text was updated successfully, but these errors were encountered: