@Test public void try_to_move_does_not_support_jumping_states() { TestLifeCycleListener listener = new TestLifeCycleListener(); Lifecycle lifecycle = new Lifecycle(ProcessId.ELASTICSEARCH, asList(listener)); assertThat(lifecycle.getState()).isEqualTo(INIT); assertThat(listener.states).isEmpty(); assertThat(lifecycle.tryToMoveTo(STARTED)).isFalse(); assertThat(lifecycle.getState()).isEqualTo(INIT); assertThat(listener.states).isEmpty(); assertThat(lifecycle.tryToMoveTo(STARTING)).isTrue(); assertThat(lifecycle.getState()).isEqualTo(STARTING); assertThat(listener.states).containsOnly(STARTING); }
public boolean start(Supplier<ProcessMonitor> commandLauncher) { if (!lifecycle.tryToMoveTo(Lifecycle.State.STARTING)) { // has already been started return false; } try { this.process = commandLauncher.get(); } catch (RuntimeException e) { LOG.error("Fail to launch process [{}]", processId.getKey(), e); lifecycle.tryToMoveTo(Lifecycle.State.STOPPED); throw e; } this.stdOutGobbler = new StreamGobbler(process.getInputStream(), processId.getKey()); this.stdOutGobbler.start(); this.stdErrGobbler = new StreamGobbler(process.getErrorStream(), processId.getKey()); this.stdErrGobbler.start(); this.stopWatcher.start(); this.eventWatcher.start(); // Could be improved by checking the status "up" in shared memory. // Not a problem so far as this state is not used by listeners. lifecycle.tryToMoveTo(Lifecycle.State.STARTED); return true; }
/** * Sends kill signal and awaits termination. No guarantee that process is gracefully terminated (=shutdown hooks * executed). It depends on OS. */ public void stop(long timeout, TimeUnit timeoutUnit) { if (lifecycle.tryToMoveTo(Lifecycle.State.STOPPING)) { stopGracefully(timeout, timeoutUnit); if (process != null && process.isAlive()) { LOG.info("{} failed to stop in a timely fashion. Killing it.", processId.getKey()); } // enforce stop and clean-up even if process has been gracefully stopped stopForcibly(); } else { // already stopping or stopped waitForDown(); } }
@Test public void no_state_can_not_move_to_itself() { for (Lifecycle.State state : Lifecycle.State.values()) { assertThat(newLifeCycle(state).tryToMoveTo(state)).isFalse(); } }
@Test public void can_move_to_STARTED_from_STARTING_only() { for (Lifecycle.State state : Lifecycle.State.values()) { TestLifeCycleListener listener = new TestLifeCycleListener(); boolean tryToMoveTo = newLifeCycle(state, listener).tryToMoveTo(STARTED); if (state == STARTING) { assertThat(tryToMoveTo).as("from state " + state).isTrue(); assertThat(listener.states).containsOnly(STARTED); } else { assertThat(tryToMoveTo).as("from state " + state).isFalse(); assertThat(listener.states).isEmpty(); } } }
@Test public void can_move_to_STOPPING_from_STARTING_STARTED_only() { for (Lifecycle.State state : Lifecycle.State.values()) { TestLifeCycleListener listener = new TestLifeCycleListener(); boolean tryToMoveTo = newLifeCycle(state, listener).tryToMoveTo(STOPPING); if (state == STARTING || state == STARTED) { assertThat(tryToMoveTo).as("from state " + state).isTrue(); assertThat(listener.states).containsOnly(STOPPING); } else { assertThat(tryToMoveTo).as("from state " + state).isFalse(); assertThat(listener.states).isEmpty(); } } }
public void stopForcibly() { eventWatcher.interrupt(); stopWatcher.interrupt(); if (process != null) { process.destroyForcibly(); waitForDown(); process.closeStreams(); } if (stdOutGobbler != null) { StreamGobbler.waitUntilFinish(stdOutGobbler); stdOutGobbler.interrupt(); } if (stdErrGobbler != null) { StreamGobbler.waitUntilFinish(stdErrGobbler); stdErrGobbler.interrupt(); } lifecycle.tryToMoveTo(Lifecycle.State.STOPPED); }
public boolean start(Supplier<ProcessMonitor> commandLauncher) { if (!lifecycle.tryToMoveTo(Lifecycle.State.STARTING)) { // has already been started return false; } try { this.process = commandLauncher.get(); } catch (RuntimeException e) { LOG.error("Fail to launch process [{}]", processId.getKey(), e); lifecycle.tryToMoveTo(Lifecycle.State.STOPPED); throw e; } this.stdOutGobbler = new StreamGobbler(process.getInputStream(), processId.getKey()); this.stdOutGobbler.start(); this.stdErrGobbler = new StreamGobbler(process.getErrorStream(), processId.getKey()); this.stdErrGobbler.start(); this.stopWatcher.start(); this.eventWatcher.start(); // Could be improved by checking the status "up" in shared memory. // Not a problem so far as this state is not used by listeners. lifecycle.tryToMoveTo(Lifecycle.State.STARTED); return true; }
/** * Sends kill signal and awaits termination. No guarantee that process is gracefully terminated (=shutdown hooks * executed). It depends on OS. */ public void stop(long timeout, TimeUnit timeoutUnit) { if (lifecycle.tryToMoveTo(Lifecycle.State.STOPPING)) { stopGracefully(timeout, timeoutUnit); if (process != null && process.isAlive()) { LOG.info("{} failed to stop in a timely fashion. Killing it.", processId.getKey()); } // enforce stop and clean-up even if process has been gracefully stopped stopForcibly(); } else { // already stopping or stopped waitForDown(); } }
public void stopForcibly() { eventWatcher.interrupt(); stopWatcher.interrupt(); if (process != null) { process.destroyForcibly(); waitForDown(); process.closeStreams(); } if (stdOutGobbler != null) { StreamGobbler.waitUntilFinish(stdOutGobbler); stdOutGobbler.interrupt(); } if (stdErrGobbler != null) { StreamGobbler.waitUntilFinish(stdErrGobbler); stdErrGobbler.interrupt(); } lifecycle.tryToMoveTo(Lifecycle.State.STOPPED); }