-
Notifications
You must be signed in to change notification settings - Fork 42
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
ConfigureAwait(false) for close stream/consumer/producer, query offset and create producer #231
ConfigureAwait(false) for close stream/consumer/producer, query offset and create producer #231
Conversation
…s, query offset and create producer
@iuribrindeiro thanks for doing this. I have added a code analysis warning for I can get that this weekend, but if you do that work, be sure to keep your branch updated so we don't duplicate it. Thanks! |
Awesome! I'll do a few and keep updaing this PR |
@lukebakken I've set the |
Thank you @iuribrindeiro |
* Improve the reconnect * Handle some edge cases where the producer or consumer could go into a deadlock waiting for the semaphore. * Add the Cancellation token producer side and call the token cancellation when the producer and the consumer are forced to disconnect. * ConfigureAwait(false) for close stream/consumer/producer, query offset and create producer (#231) * ConfigureAwait(false) for close stream, consumer, producer connections, query offset and create producer * Apply roslynator.exe fixes * Do not warn about ConfigureAwait in tests, fix more instances * Fixing ConfigureAwait(false) for the rest of the lib * Add test for close the producer/consumer in different threads * Improve super stream example --------- Co-authored-by: Luke Bakken <luke@bakken.io> Signed-off-by: Gabriele Santomaggio <G.santomaggio@gmail.com> Co-authored-by: Iuri Brindeiro <iuri@fullstacklabs.co>
The changes in #230 were good but not enough to fix deadlocks when trying to close consumers connections.
Adding a
ConfigureAwait(false)
only toMaybeClose
was not enough because when it was being called byRawConsumer.Close
like this:A deadlock was still happening.
The
ConfigureAwait
in .NET is kind of... eeh.. stupid. You basically have to call it for everyawait
you do inside library code because, other wise, you would be getting the application'sSynchronizationContext
. Since this code is supposed to be used anywhere, we don't actually know how the clientSynchronizationContext
works, we don't know it's limitations. If it is a single threadSynchronizationContext
, for example, we would be causing a deadlock awaiting on the current thread to finish a job that it self started.See the following example:
On the example above, calling
ConfigureAwait(false)
on theTask.Delay(1000)
method won't be enough. It will, for unblocking code afterTask.Delay(1000)
, but once we are back to the lastawait
(inLibraryCode
method), the applicationSynchronizationContext
will once again be used. That way we are now waiting on the current thread to finish work that it self started, making it busy to listen for the completed stated ofDoWork
. Deadlock.If we simply add:
It will now be the app responsability to deal with the task returned by the
Task LibraryCode
method.It could either call an
await
like it is doing in our example above (but if so, would need to call.ConfigureAwait(false)
on theLibraryCode
as well. Same thing as the last paragraph), or it could do awhile(!task.IsCompleted) {}
to run code only after the task is completed.TLDR:
ConfigureAwait(false)
everywhere for library code.Reference: https://devblogs.microsoft.com/dotnet/configureawait-faq/#:~:text=ConfigureAwait(false)%20involves%20a%20task,context%20that%20was%20there%20previously.