Skip to content
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: adds a handler to gracefully shutdown #5895

Merged
merged 3 commits into from
Jul 30, 2020

Conversation

rodesai
Copy link
Contributor

@rodesai rodesai commented Jul 29, 2020

Description

Couple changes related to application lifecycle management. Firstly, adds a shutdown handler
that gracefully shuts down the service when the jvm determines its time to shut down (e.g.
when it receives a termination signal). Secondly, this patch reorganizes some of the startup,
steady-state, and shutdown code to make shutdown easier to reason about. Specifically, all
these methods are now called from the same thread, so both the thread-safety and order of
execution are guaranteed. All the shutdown hook does is notify the main thread and then wait
for it to exit.

Testing done

unit test to ensure shutdown handler is called
manual testing of shutdown process

Reviewer checklist

  • Ensure docs are updated if necessary. (eg. if a user visible feature is being added or changed).
  • Ensure relevant issues are linked (description should include text like "Fixes #")

@rodesai rodesai requested a review from a team as a code owner July 29, 2020 08:38
Copy link
Contributor

@vcrfxia vcrfxia left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @rodesai -- LGTM with a couple questions inline.

@@ -129,12 +129,17 @@ public void startAsync() {
versionChecker.start(KsqlModuleType.SERVER, properties);
} catch (final Exception e) {
log.error("Failed to start KSQL Server with query file: " + queriesFile, e);
triggerShutdown();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Was it a bug that this was here previously, since it means triggerShutdown() was being called from both StandaloneExecutor and KsqlServerMain? (Checking my understanding for why this was removed.)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think it's a bug necessarily (since triggerShutdown is idempotent). Just not needed.

// Given:
final Capture<Runnable> captureShutdownHandler = newCapture();
shutdownHandler.execute(capture(captureShutdownHandler));
executable.notifyTerminated();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not understanding this test. Are we missing an expectLastCall(); after this line?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oof yeah - fixed

@apurvam
Copy link
Contributor

apurvam commented Jul 29, 2020

Let's target this on 6.0.x / 0.10.x and then merge forward to 0.11.x and master.

@rodesai rodesai changed the base branch from master to 6.0.x July 29, 2020 19:46
@rodesai rodesai requested a review from JimGalasyn as a code owner July 29, 2020 19:46
@rodesai rodesai changed the base branch from 6.0.x to master July 29, 2020 19:46
Couple changes related to application lifecycle management. Firstly, adds a shutdown handler
that gracefully shuts down the service when the jvm determines its time to shut down (e.g.
when it receives a termination signal). Secondly, this patch reorganizes some of the startup,
steady-state, and shutdown code to make shutdown easier to reason about. Specifically, all
these methods are now called from the same thread, so both the thread-safety and order of
execution are guaranteed. All the shutdown hook does is notify the main thread and then wait
for it to exit.
@apurvam apurvam added this to the 0.11.0 milestone Jul 29, 2020
@rodesai rodesai changed the base branch from master to 6.0.x July 29, 2020 20:18
Copy link
Member

@JimGalasyn JimGalasyn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sweet!

@rodesai rodesai merged commit 5fbf171 into confluentinc:6.0.x Jul 30, 2020
vcrfxia pushed a commit that referenced this pull request Jul 30, 2020
* fix: adds a handler to gracefully shutdown service

Couple changes related to application lifecycle management. Firstly, adds a shutdown handler
that gracefully shuts down the service when the jvm determines its time to shut down (e.g.
when it receives a termination signal). Secondly, this patch reorganizes some of the startup,
steady-state, and shutdown code to make shutdown easier to reason about. Specifically, all
these methods are now called from the same thread, so both the thread-safety and order of
execution are guaranteed. All the shutdown hook does is notify the main thread and then wait
for it to exit.
@@ -305,7 +304,7 @@ public void startAsync() {
pullQueryExecutor
);

startAsyncThread = Thread.currentThread();
startAsyncThreadRef.set(Thread.currentThread());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we use CAS if startAsync is mistakenly triggered multiple times?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense. We could move this to be the first thing in the method and then throw if it's ever non-null.

}

void tryStartApp() throws Exception {
final CountDownLatch latch = new CountDownLatch(1);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For my own clarification: why we design tryStartApp itself to be blocking until shutdown, instead of letting this function to return after startup procedure completed, and then having another shutdown function that block until shutdown completes?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this might just be my C background talking, but the pattern I've gotten used to is to have the main thread own the application's lifecycle. It starts up all services, waits for a notification to initiate shutdown, and then orchestrates the shutdown process. This pattern makes a great deal of sense in that world because usually you'd write your shutdown in response to a signal, and a signal handler should not block. I think following this pattern in Java makes sense too for the following reasons:

  • I wasn't totally sure what constraints the jvm would run the shutdown thread under. It seemed simplest to just have it do as little as possible and let the main thread manage shutdown
  • This gives you the guarantee that start is only ever called before shutdown, so it's easier to reason about the two (no synchronization needed, don't need to worry about entering start after calling shutdown).

rodesai added a commit to rodesai/ksql that referenced this pull request Jul 30, 2020
* fix: adds a handler to gracefully shutdown service

Couple changes related to application lifecycle management. Firstly, adds a shutdown handler
that gracefully shuts down the service when the jvm determines its time to shut down (e.g.
when it receives a termination signal). Secondly, this patch reorganizes some of the startup,
steady-state, and shutdown code to make shutdown easier to reason about. Specifically, all
these methods are now called from the same thread, so both the thread-safety and order of
execution are guaranteed. All the shutdown hook does is notify the main thread and then wait
for it to exit.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants