Adds BrooklynShutdownHooks.invokeTerminateOnShutdown(managementContext) Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/ab26150b Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/ab26150b Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/ab26150b
Branch: refs/pull/1406/merge Commit: ab26150b5dc24494d6473cb88546e551493fe24f Parents: a972f00 Author: Aled Sage <aled.s...@gmail.com> Authored: Thu May 22 09:34:04 2014 +0100 Committer: Aled Sage <aled.s...@gmail.com> Committed: Thu May 22 09:34:04 2014 +0100 ---------------------------------------------------------------------- .../entity/basic/BrooklynShutdownHooks.java | 49 +++++++++++++++++--- .../entity/basic/BrooklynShutdownHooksTest.java | 25 ++++++++++ 2 files changed, 67 insertions(+), 7 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ab26150b/core/src/main/java/brooklyn/entity/basic/BrooklynShutdownHooks.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/brooklyn/entity/basic/BrooklynShutdownHooks.java b/core/src/main/java/brooklyn/entity/basic/BrooklynShutdownHooks.java index 979422b..928f918 100644 --- a/core/src/main/java/brooklyn/entity/basic/BrooklynShutdownHooks.java +++ b/core/src/main/java/brooklyn/entity/basic/BrooklynShutdownHooks.java @@ -9,8 +9,12 @@ import org.slf4j.LoggerFactory; import brooklyn.entity.Entity; import brooklyn.entity.trait.Startable; +import brooklyn.management.ManagementContext; import brooklyn.management.Task; +import brooklyn.management.internal.ManagementContextInternal; import brooklyn.util.collections.MutableMap; +import brooklyn.util.exceptions.Exceptions; +import brooklyn.util.exceptions.RuntimeInterruptedException; import brooklyn.util.javalang.Threads; import com.google.common.annotations.VisibleForTesting; @@ -22,11 +26,23 @@ public class BrooklynShutdownHooks { private static final AtomicBoolean isShutdownHookRegistered = new AtomicBoolean(); private static final List<Entity> entitiesToStopOnShutdown = Lists.newArrayList(); + private static final List<ManagementContextInternal> managementContextsToTermianteOnShutdown = Lists.newArrayList(); public static void invokeStopOnShutdown(Entity entity) { synchronized (entitiesToStopOnShutdown) { entitiesToStopOnShutdown.add(entity); } + addShutdownHookIfNotAlready(); + } + + public static void invokeTerminateOnShutdown(ManagementContext managementContext) { + synchronized (entitiesToStopOnShutdown) { + managementContextsToTermianteOnShutdown.add((ManagementContextInternal) managementContext); + } + addShutdownHookIfNotAlready(); + } + + private static void addShutdownHookIfNotAlready() { if (isShutdownHookRegistered.compareAndSet(false, true)) { Threads.addShutdownHook(new BrooklynShutdownHookJob()); } @@ -37,21 +53,40 @@ public class BrooklynShutdownHooks { @SuppressWarnings({ "unchecked", "rawtypes" }) @Override public void run() { + // First stop entities; on interrupt, abort waiting for tasks - but let shutdown hook continue synchronized (entitiesToStopOnShutdown) { - log.info("Brooklyn stopOnShutdown shutdown-hook invoked: stopping "+entitiesToStopOnShutdown); + log.info("Brooklyn stopOnShutdown shutdown-hook invoked: stopping entities: "+entitiesToStopOnShutdown); List<Task> stops = new ArrayList<Task>(); for (Entity entity: entitiesToStopOnShutdown) { try { stops.add(entity.invoke(Startable.STOP, new MutableMap())); - } catch (Exception exc) { - log.debug("stopOnShutdown of "+entity+" returned error: "+exc, exc); + } catch (RuntimeException exc) { + log.debug("stopOnShutdown of "+entity+" returned error (continuing): "+exc, exc); + } + } + try { + for (Task t: stops) { + try { + log.debug("stopOnShutdown of {} completed: {}", t, t.get()); + } catch (Exception e) { + log.debug("stopOnShutdown of "+t+" returned error (continuing): "+e, e); + Exceptions.propagateIfFatal(e); + } } + } catch (RuntimeInterruptedException e) { + Thread.currentThread().interrupt(); + log.debug("stopOnShutdown interrupted while waiting for entity-stop tasks; continuing: "+e); } - for (Task t: stops) { + } + + // Then terminate management contexts + synchronized (managementContextsToTermianteOnShutdown) { + log.info("Brooklyn terminateOnShutdown shutdown-hook invoked: terminating management contexts: "+managementContextsToTermianteOnShutdown); + for (ManagementContextInternal managementContext: managementContextsToTermianteOnShutdown) { try { - log.debug("stopOnShutdown of {} completed: {}", t, t.get()); - } catch (Exception exc) { - log.debug("stopOnShutdown of "+t+" returned error: "+exc, exc); + managementContext.terminate(); + } catch (RuntimeException e) { + log.info("terminateOnShutdown of "+managementContext+" returned error (continuing): "+e, e); } } } http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/ab26150b/core/src/test/java/brooklyn/entity/basic/BrooklynShutdownHooksTest.java ---------------------------------------------------------------------- diff --git a/core/src/test/java/brooklyn/entity/basic/BrooklynShutdownHooksTest.java b/core/src/test/java/brooklyn/entity/basic/BrooklynShutdownHooksTest.java index ba65f46..7961cf6 100644 --- a/core/src/test/java/brooklyn/entity/basic/BrooklynShutdownHooksTest.java +++ b/core/src/test/java/brooklyn/entity/basic/BrooklynShutdownHooksTest.java @@ -1,5 +1,6 @@ package brooklyn.entity.basic; +import static org.testng.Assert.assertFalse; import static org.testng.Assert.assertTrue; import org.testng.annotations.AfterMethod; @@ -7,11 +8,13 @@ import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; import brooklyn.entity.proxying.EntitySpec; +import brooklyn.management.ManagementContext; import brooklyn.test.entity.TestApplication; import brooklyn.test.entity.TestEntity; public class BrooklynShutdownHooksTest { + private ManagementContext managementContext; private TestApplication app; private TestEntity entity; @@ -19,6 +22,7 @@ public class BrooklynShutdownHooksTest { public void setUp() { app = ApplicationBuilder.newManagedApp(TestApplication.class); entity = app.createAndManageChild(EntitySpec.create(TestEntity.class)); + managementContext = app.getManagementContext(); } @AfterMethod(alwaysRun=true) @@ -34,4 +38,25 @@ public class BrooklynShutdownHooksTest { assertTrue(entity.getCallHistory().contains("stop")); } + + @Test + public void testInvokeTerminateManagementContextOnShutdown() throws Exception { + BrooklynShutdownHooks.invokeTerminateOnShutdown(managementContext); + BrooklynShutdownHooks.BrooklynShutdownHookJob job = new BrooklynShutdownHooks.BrooklynShutdownHookJob(); + job.run(); + + assertFalse(managementContext.isRunning()); + } + + // Should first stop entities, then terminate management contexts + @Test + public void testInvokeStopEntityAndTerminateManagementContextOnShutdown() throws Exception { + BrooklynShutdownHooks.invokeTerminateOnShutdown(managementContext); + BrooklynShutdownHooks.invokeStopOnShutdown(entity); + BrooklynShutdownHooks.BrooklynShutdownHookJob job = new BrooklynShutdownHooks.BrooklynShutdownHookJob(); + job.run(); + + assertTrue(entity.getCallHistory().contains("stop")); + assertFalse(managementContext.isRunning()); + } }