-
Notifications
You must be signed in to change notification settings - Fork 289
Stronger Shutdown Semantics in Database #90
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
Conversation
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.
Looks good, but a couple suggestions.
@@ -134,6 +142,26 @@ public void run() { | |||
} | |||
} | |||
|
|||
private void destroyInternal(final Context ctx) { |
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 seems to be a subset of interruptInternal() [it interrupts all the repos but never calls ctx.stop()]. Could we just use interruptInternal()?
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.
We were effectively calling interruptInternal()
before this PR. But it only calls ctx.stop()
conditionally. Specifically, it won't close the context when there are active event listeners. The new destroy()
method has stronger semantics in the sense it will always stop the context.
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.
Yeah. My point was that destroy() could call interrupt() and then call ctx.stop() instead of duplicating this code. I don't care that strongly though.
if (!isClosed) { | ||
executorService.execute(new Runnable() { | ||
@Override | ||
public void run() { |
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 you should probably duplicate the isClosed check here, since we're now on the correct thread (the one that mutates isClosed).
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.
onClosed()
method already has the check:
private void onClosed() {
if (!isClosed) {
if (logger.logsDebug()) {
logger.debug("closing itself");
}
shutdown();
}
conn = null;
if (keepAlive != null) {
keepAlive.cancel(false);
keepAlive = null;
}
}
eventTarget.shutdown(); | ||
runLoop.shutdown(); | ||
if (eventTarget != null) { | ||
eventTarget.shutdown(); |
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.
should you set them to null too?
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 them to remain non-null for Context.restartServices()
to work. In case of a destroy()
it won't really matter either way.
There are several limitations in the existing shutdown/destroy logic of
FirebaseDatabase
:ctx.stop()
is called conditionally, and this doesn't always seem to happen.onClosed()
fire late, usually afterRunLoop.shutdown()
has been called. In this case, theRunLoop
is silently re-initialized to handle the late event.Users have observed dangling background threads left by the SDK due to the above issues.
To resolve these problems, this PR:
RepoManager.destroy()
method that always callsctx.stop()
.onClosed()
events, thus preventing theRunLoop
from re-initializing after shutdown.removeOnCancelPolicy()
on theRevivingScheduledExecutor
, which removes cancelled tasks from the job queue thus facilitating early termination of threads (the underlyingScheduledThreadPoolExecutor
won't shutdown threads, as long as there are jobs in the queue, even if they are cancelled).I have tested this PR locally, and verified that all database-related threads are shut down upon calling
FirebaseApp.delete()
.