-
Notifications
You must be signed in to change notification settings - Fork 772
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
Fix double shutdown #1017
Fix double shutdown #1017
Conversation
Codecov Report
@@ Coverage Diff @@
## master #1017 +/- ##
==========================================
- Coverage 75.56% 75.52% -0.05%
==========================================
Files 222 222
Lines 6208 6210 +2
==========================================
- Hits 4691 4690 -1
- Misses 1517 1520 +3
|
@@ -80,14 +82,24 @@ public void Dispose() | |||
|
|||
protected virtual void Dispose(bool disposing) | |||
{ | |||
try | |||
if (this.disposed) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is probably fine but I don't think necessarily it is the standard/preferred pattern. This is what I'm used to doing:
public void Shutdown()
{
if (!IsRunning) return;
// Shutdown
IsRunning = false;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
~ClassName()
{
Dispose(false);
}
protected virtual void Dispose(bool disposing)
{
Shutdown();
if (disposing && !disposed)
{
// Call dispose on owned refs.
disposed = true;
}
}
The reason for that is if someone makes a mistake and forgets to call Dispose, you want the finalizer to still call Shutdown. Because it might have a thread or something it needs to signal which will prevent the process from spinning down.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see your point. I was concerned about running complex managed code in Finalizer thread as it might clog the entire GC (which turns an application developer's problem into a runtime library developer's problem). Thoughts?
For example, I would avoid running context manipulation code in the Finalizer thread.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@reyang Also a good point. I suppose it's a tradeoff. We want users to call Dispose, and most will, negating any hit, but we need to utilize the finalizer to do the cleanup just in case the user messes up?
@noahfalk @tarekgh Would love to get an expert opinion on this if you guys have the time. Any official guidance on calling Shutdown/Close in Dispose/Finalizer?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is something we can change later, not necessarily blocking the PR.
Created #1024 for tracking.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I didn't look at the details, but here is the guidlines for disposing in general https://docs.microsoft.com/en-us/dotnet/standard/garbage-collection/implementing-dispose. it is recommended to use SafeHandle instead of providing finalizer.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sent a comment, but LGTM.
47c269e
to
69f4744
Compare
} | ||
|
||
this.disposed = true; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we need set disposed
to true
if exception happened in the call to ShutdownAsync
, or just throw the exception out?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we need to set to true as dispose is not supposed to fail / retry.
Changes
CompositeActivityProcessor
(there is a similar bug inFanOutActivityProcessor
which I'm not fixing in this PR).For significant contributions please make sure you have completed the following items: