-
Notifications
You must be signed in to change notification settings - Fork 591
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
ObjectDisposedException when connection is closed from the server #1749
Comments
I encountered similar problem, but kind of backwards, because this ObjectDisposedException caused closing connection with such close reason.
The error happened when there was significant load and RabbitMQ responses were several times slower than usual. But I haven't got to the bottom of issue and I don't know the root cause. I'm not sure if it's library itself or usage of the library causing the error, but I can't find any documentation about handling this. Without this timeout some of close requests were running for really long (maybe even infinitely? Some deadlock? There was no channel on server side), so the timeout was added to unblock the thread. To be sure I also checked without running CloseAsync on IChannel at all, but it haven't helped. |
@ramonsmits I still have yet to hit an Here is my test application: It starts a consumer, then repeatedly uses the HTTP API to close the connection. I have left it running a long time in my test environment, and have yet to see Maybe there's something up with my code? If you can take a look, I'd appreciate it. |
I managed to reproduce the problem I described. I called I think the |
For I/O exceptions, it is. And it can and does trigger a connection recovery. For when a connection is closed, the methods should simply be made idempotent. And |
Yep, that's how it's supposed to work 😉 Thank you for the details, @ZajacPiotr98. Since you can reproduce this issue, would you be able to test a pull request once I open it? |
I tested these changes and it's not resolving problem for the case I run. It was simple test:
Also, for this test the
I'm not completely sure what is handled in the |
@ZajacPiotr98 as far as I understand, #1752 focuses on connection objects and you are trying with channels. Their (channels') behavior should generally be identical to the idea above but you and @lukebakken may be focussing on the same problem in two different places. |
@ZajacPiotr98 did you follow the same test procedure you detailed in this comment? #1752 adds a |
Yes, maybe I was not precise if it was @lukebakken I've even tried without Clumsy and had same results. Additionally, to mitigate this behavior, as workaround, I added in the app the isDisposing field, that is setting to true at the start of Disposing channel and never lets run another |
Ah, you're not awaiting the |
Fixes #1749 * Add test project * Add `FirstChanceException` logging. * Add code to repeatedly close connection. * Allow passing hostname to GH-1749 program as the first arg. * Toxiproxy tests fixup. * Standardize on `_disposedValue` name. * Ensure `_disposedValue` is set in `finally` block. * Add lock object for disposal of Channels and Connections. Note: a `SemaphoreSlim` can't be used because it must be disposed as well, and that can't happen cleanly in a `Dispose` method.
@ZajacPiotr98 - please give my PR a test. I've added what amounts to a "Disposing" state to channels and connections, that only allows one thread to do the disposal. |
I will be able to test it next week. But the problem is not with the multiple dispose. I'm awaiting the dispose invocation and it only happens when multiple threads do dispose in the same time. But, like I mentioned I corrected this behavior with workaround on my side. The problem, that is really impacting application is: I think invoking dispose on the exception or when channel is no longer needed should not close entire connection. But it does sometimes, when disposal of semaphores finishes before I only used double dispose without awaiting as an example to reproduce that issue. I couldn't find a way to reproduce it same as on the environment under load tests as there is significant load and thus closing channel is taking more time. I asked about it here:
|
Well, concurrent disposal is a scenario I haven't seen mentioned here, I only thought of the case where a connectio nor channel is disposed N times sequentially. Given that shared use of channels was not supported by this library till 7.0, and that concurrent disposal is not necessarily supported by a lot of libraries for other data services, this may be out of scope for this client. Sharing one-off channels for passive declares between threads seems unnecessary to me but maybe that's an inevitable effect of adopting tasks for the parts that interact with RabbitMQ :( |
Describe the bug
Logging FirstChanceExceptions shows some strange ObjectDisposedException:
https://github.com/rabbitmq/rabbitmq-dotnet-client/blob/v7.0.0/projects/RabbitMQ.Client/Impl/Connection.Heartbeat.cs#L164 accessing
.Token
here can result in an ObjectDisposedException. That is catched, but the comment states that its for the timerThe SetSessionClosingAsync uses a
_closingSemaphore
that can already be disposed. It seems this isn't gracefully handled in the stacktrace.https://github.com/rabbitmq/rabbitmq-dotnet-client/blob/v7.0.0/projects/RabbitMQ.Client/Impl/MainSession.cs
I'm not sure if this is causing issues but looking at the code it might be needed that these code paths all need to have exception handling to prevent code not to terminate if these ObjectDisposedExceptions are to be expected.
Reproduction steps
Do this a couple of times and you'll see the related exception
Expected behavior
gracefully handle ObjectDisposedException on all code paths for closed connections
Additional context
No response
The text was updated successfully, but these errors were encountered: