Ensure Singleton Closes Any Opened Object During Concurrent Open/Close #173
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
See Issue = #172
Issue Overview
When using the singleton class, running GetOrCreateAsync() & CloseAsync() in a particular order, the singleton will end up disposed but with Value remaining populated.
This mainly causes an issue because it is the backing for
FaultTolerantAmqpObject<T>
. So, a concurrent open/close may cause an amqpobject that we would expect to be closed to remain opened in the background.Issue Reproduction
The unit test in this PR contains a reproduction directly against the singleton class.
This project reproduces the issue directly using the FaultTolerantAmqpObject class https://github.com/paulsavides/ServiceBusTesting/tree/b3a5df45c67af84a816ec935d5b6bb749d915b80/ReproAmqp
When using the changes I have made in this PR, have confirmed the issues are fixed.
Issue Fix
Generally just adding back a bit of code that was removed in this commit 8366a43
After actually opening the object, just add the following check:
I briefly considered throwing an ObjectDisposedException here, however, the task result has already been set at this point so setting an exception on the task completion source would not work. Additionally, moving the IsDisposed check before the OnCreate() or SetResult would leave in a race condition so, without introducing additional locking we're stuck just returning a closed object here.
Also added a
TryRemove()
around both places we may callOnSafeClose()
. This is just to try and ensure only one thread will actually call the remove.Please let me know if you require any changes here, if this is the complete wrong approach or if I have completely misdiagnosed the issue.
Thank you for taking a look,
Paul Savides