@@ -17,9 +17,8 @@ | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.application.process; | |||
package org.sonar.application; | |||
import org.sonar.application.FileSystem; | |||
import org.sonar.application.config.AppSettings; | |||
import org.sonar.process.ProcessId; | |||
import org.sonar.process.sharedmemoryfile.DefaultProcessCommands; |
@@ -35,7 +35,7 @@ import static org.sonar.application.NodeLifecycle.State.STOPPED; | |||
import static org.sonar.application.NodeLifecycle.State.STOPPING; | |||
/** | |||
* Lifecycle of the cluster node, consolidating the states | |||
* ManagedProcessLifecycle of the cluster node, consolidating the states | |||
* of child processes. | |||
*/ | |||
class NodeLifecycle { |
@@ -17,10 +17,11 @@ | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.application.process; | |||
package org.sonar.application; | |||
import java.io.Closeable; | |||
import org.sonar.application.command.AbstractCommand; | |||
import org.sonar.application.process.ManagedProcess; | |||
public interface ProcessLauncher extends Closeable { | |||
@@ -32,5 +33,5 @@ public interface ProcessLauncher extends Closeable { | |||
* | |||
* @throws IllegalStateException if an error occurs | |||
*/ | |||
ProcessMonitor launch(AbstractCommand command); | |||
ManagedProcess launch(AbstractCommand command); | |||
} |
@@ -17,7 +17,7 @@ | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.application.process; | |||
package org.sonar.application; | |||
import com.google.common.net.HostAndPort; | |||
import java.io.File; | |||
@@ -38,6 +38,9 @@ import org.sonar.application.command.JavaCommand; | |||
import org.sonar.application.command.JvmOptions; | |||
import org.sonar.application.es.EsConnectorImpl; | |||
import org.sonar.application.es.EsInstallation; | |||
import org.sonar.application.process.EsManagedProcess; | |||
import org.sonar.application.process.ManagedProcess; | |||
import org.sonar.application.process.ProcessCommandsManagedProcess; | |||
import org.sonar.process.FileUtils2; | |||
import org.sonar.process.ProcessId; | |||
import org.sonar.process.sharedmemoryfile.AllProcessesCommands; | |||
@@ -74,7 +77,7 @@ public class ProcessLauncherImpl implements ProcessLauncher { | |||
allProcessesCommands.close(); | |||
} | |||
public ProcessMonitor launch(AbstractCommand command) { | |||
public ManagedProcess launch(AbstractCommand command) { | |||
EsInstallation esInstallation = command.getEsInstallation(); | |||
if (esInstallation != null) { | |||
cleanupOutdatedEsData(esInstallation); | |||
@@ -95,10 +98,10 @@ public class ProcessLauncherImpl implements ProcessLauncher { | |||
if (processId == ProcessId.ELASTICSEARCH) { | |||
checkArgument(esInstallation != null, "Incorrect configuration EsInstallation is null"); | |||
EsConnectorImpl esConnector = new EsConnectorImpl(esInstallation.getClusterName(), singleton(HostAndPort.fromParts(esInstallation.getHost(), esInstallation.getPort()))); | |||
return new EsProcessMonitor(process, processId, esConnector); | |||
return new EsManagedProcess(process, processId, esConnector); | |||
} else { | |||
ProcessCommands commands = allProcessesCommands.createAfterClean(processId.getIpcIndex()); | |||
return new ProcessCommandsProcessMonitor(process, processId, commands); | |||
return new ProcessCommandsManagedProcess(process, processId, commands); | |||
} | |||
} catch (Exception e) { | |||
// just in case |
@@ -32,17 +32,16 @@ import org.sonar.application.command.AbstractCommand; | |||
import org.sonar.application.command.CommandFactory; | |||
import org.sonar.application.config.AppSettings; | |||
import org.sonar.application.config.ClusterSettings; | |||
import org.sonar.application.process.Lifecycle; | |||
import org.sonar.application.process.ProcessEventListener; | |||
import org.sonar.application.process.ProcessLauncher; | |||
import org.sonar.application.process.ManagedProcessLifecycle; | |||
import org.sonar.application.process.ManagedProcessEventListener; | |||
import org.sonar.application.process.ProcessLifecycleListener; | |||
import org.sonar.application.process.ProcessMonitor; | |||
import org.sonar.application.process.SQProcess; | |||
import org.sonar.application.process.ManagedProcess; | |||
import org.sonar.application.process.ManagedProcessHandler; | |||
import org.sonar.process.ProcessId; | |||
import static org.sonar.application.process.SQProcess.Timeout.newTimeout; | |||
import static org.sonar.application.process.ManagedProcessHandler.Timeout.newTimeout; | |||
public class SchedulerImpl implements Scheduler, ProcessEventListener, ProcessLifecycleListener, AppStateListener { | |||
public class SchedulerImpl implements Scheduler, ManagedProcessEventListener, ProcessLifecycleListener, AppStateListener { | |||
private static final Logger LOG = LoggerFactory.getLogger(SchedulerImpl.class); | |||
@@ -57,12 +56,12 @@ public class SchedulerImpl implements Scheduler, ProcessEventListener, ProcessLi | |||
private final AtomicBoolean firstWaitingEsLog = new AtomicBoolean(true); | |||
private final AtomicBoolean restartRequested = new AtomicBoolean(false); | |||
private final AtomicBoolean restarting = new AtomicBoolean(false); | |||
private final EnumMap<ProcessId, SQProcess> processesById = new EnumMap<>(ProcessId.class); | |||
private final EnumMap<ProcessId, ManagedProcessHandler> processesById = new EnumMap<>(ProcessId.class); | |||
private final AtomicInteger operationalCountDown = new AtomicInteger(); | |||
private final AtomicInteger stopCountDown = new AtomicInteger(0); | |||
private HardStopperThread hardStopperThread; | |||
private RestarterThread restarterThread; | |||
private long processWatcherDelayMs = SQProcess.DEFAULT_WATCHER_DELAY_MS; | |||
private long processWatcherDelayMs = ManagedProcessHandler.DEFAULT_WATCHER_DELAY_MS; | |||
public SchedulerImpl(AppSettings settings, AppReloader appReloader, CommandFactory commandFactory, | |||
ProcessLauncher processLauncher, AppState appState) { | |||
@@ -87,7 +86,7 @@ public class SchedulerImpl implements Scheduler, ProcessEventListener, ProcessLi | |||
processesById.clear(); | |||
for (ProcessId processId : ClusterSettings.getEnabledProcesses(settings)) { | |||
SQProcess process = SQProcess.builder(processId) | |||
ManagedProcessHandler process = ManagedProcessHandler.builder(processId) | |||
.addProcessLifecycleListener(this) | |||
.addEventListener(this) | |||
.setWatcherDelayMs(processWatcherDelayMs) | |||
@@ -108,14 +107,14 @@ public class SchedulerImpl implements Scheduler, ProcessEventListener, ProcessLi | |||
} | |||
private void tryToStartEs() { | |||
SQProcess process = processesById.get(ProcessId.ELASTICSEARCH); | |||
ManagedProcessHandler process = processesById.get(ProcessId.ELASTICSEARCH); | |||
if (process != null) { | |||
tryToStartProcess(process, commandFactory::createEsCommand); | |||
} | |||
} | |||
private void tryToStartWeb() { | |||
SQProcess process = processesById.get(ProcessId.WEB_SERVER); | |||
ManagedProcessHandler process = processesById.get(ProcessId.WEB_SERVER); | |||
if (process == null) { | |||
return; | |||
} | |||
@@ -140,7 +139,7 @@ public class SchedulerImpl implements Scheduler, ProcessEventListener, ProcessLi | |||
} | |||
private void tryToStartCe() { | |||
SQProcess process = processesById.get(ProcessId.COMPUTE_ENGINE); | |||
ManagedProcessHandler process = processesById.get(ProcessId.COMPUTE_ENGINE); | |||
if (process != null && appState.isOperational(ProcessId.WEB_SERVER, true) && isEsClientStartable()) { | |||
tryToStartProcess(process, commandFactory::createCeCommand); | |||
} | |||
@@ -151,14 +150,14 @@ public class SchedulerImpl implements Scheduler, ProcessEventListener, ProcessLi | |||
return appState.isOperational(ProcessId.ELASTICSEARCH, requireLocalEs); | |||
} | |||
private void tryToStartProcess(SQProcess process, Supplier<AbstractCommand> commandSupplier) { | |||
private void tryToStartProcess(ManagedProcessHandler process, Supplier<AbstractCommand> commandSupplier) { | |||
tryToStart(process, () -> { | |||
AbstractCommand command = commandSupplier.get(); | |||
return processLauncher.launch(command); | |||
}); | |||
} | |||
private void tryToStart(SQProcess process, Supplier<ProcessMonitor> processMonitorSupplier) { | |||
private void tryToStart(ManagedProcessHandler process, Supplier<ManagedProcess> processMonitorSupplier) { | |||
try { | |||
process.start(processMonitorSupplier); | |||
} catch (RuntimeException e) { | |||
@@ -180,7 +179,7 @@ public class SchedulerImpl implements Scheduler, ProcessEventListener, ProcessLi | |||
* Returns immediately if the process is disabled in configuration. | |||
*/ | |||
private void hardStopProcess(ProcessId processId) { | |||
SQProcess process = processesById.get(processId); | |||
ManagedProcessHandler process = processesById.get(processId); | |||
if (process != null) { | |||
process.hardStop(); | |||
} | |||
@@ -217,7 +216,7 @@ public class SchedulerImpl implements Scheduler, ProcessEventListener, ProcessLi | |||
} | |||
@Override | |||
public void onProcessEvent(ProcessId processId, Type type) { | |||
public void onManagedProcessEvent(ProcessId processId, Type type) { | |||
if (type == Type.OPERATIONAL) { | |||
onProcessOperational(processId); | |||
} else if (type == Type.ASK_FOR_RESTART && restartRequested.compareAndSet(false, true)) { | |||
@@ -242,7 +241,7 @@ public class SchedulerImpl implements Scheduler, ProcessEventListener, ProcessLi | |||
} | |||
@Override | |||
public void onProcessState(ProcessId processId, Lifecycle.State to) { | |||
public void onProcessState(ProcessId processId, ManagedProcessLifecycle.State to) { | |||
switch (to) { | |||
case STOPPED: | |||
onProcessStop(processId); |
@@ -17,7 +17,7 @@ | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.application.process; | |||
package org.sonar.application; | |||
/** | |||
* Background thread that checks if a stop request |
@@ -28,15 +28,15 @@ import org.slf4j.Logger; | |||
import org.slf4j.LoggerFactory; | |||
import org.sonar.process.ProcessId; | |||
abstract class AbstractProcessMonitor implements ProcessMonitor { | |||
abstract class AbstractManagedProcess implements ManagedProcess { | |||
private static final Logger LOG = LoggerFactory.getLogger(AbstractProcessMonitor.class); | |||
private static final Logger LOG = LoggerFactory.getLogger(AbstractManagedProcess.class); | |||
private static final int EXPECTED_EXIT_VALUE = 0; | |||
protected final Process process; | |||
private final ProcessId processId; | |||
protected AbstractProcessMonitor(Process process, ProcessId processId) { | |||
protected AbstractManagedProcess(Process process, ProcessId processId) { | |||
this.process = process; | |||
this.processId = processId; | |||
} |
@@ -27,14 +27,14 @@ import org.slf4j.LoggerFactory; | |||
import org.sonar.application.es.EsConnector; | |||
import org.sonar.process.ProcessId; | |||
import static org.sonar.application.process.EsProcessMonitor.Status.CONNECTION_REFUSED; | |||
import static org.sonar.application.process.EsProcessMonitor.Status.GREEN; | |||
import static org.sonar.application.process.EsProcessMonitor.Status.KO; | |||
import static org.sonar.application.process.EsProcessMonitor.Status.RED; | |||
import static org.sonar.application.process.EsProcessMonitor.Status.YELLOW; | |||
import static org.sonar.application.process.EsManagedProcess.Status.CONNECTION_REFUSED; | |||
import static org.sonar.application.process.EsManagedProcess.Status.GREEN; | |||
import static org.sonar.application.process.EsManagedProcess.Status.KO; | |||
import static org.sonar.application.process.EsManagedProcess.Status.RED; | |||
import static org.sonar.application.process.EsManagedProcess.Status.YELLOW; | |||
public class EsProcessMonitor extends AbstractProcessMonitor { | |||
private static final Logger LOG = LoggerFactory.getLogger(EsProcessMonitor.class); | |||
public class EsManagedProcess extends AbstractManagedProcess { | |||
private static final Logger LOG = LoggerFactory.getLogger(EsManagedProcess.class); | |||
private static final int WAIT_FOR_UP_DELAY_IN_MILLIS = 100; | |||
private static final int WAIT_FOR_UP_TIMEOUT = 10 * 60; /* 1min */ | |||
@@ -44,7 +44,7 @@ public class EsProcessMonitor extends AbstractProcessMonitor { | |||
private final EsConnector esConnector; | |||
public EsProcessMonitor(Process process, ProcessId processId, EsConnector esConnector) { | |||
public EsManagedProcess(Process process, ProcessId processId, EsConnector esConnector) { | |||
super(process, processId); | |||
this.esConnector = esConnector; | |||
} |
@@ -22,7 +22,7 @@ package org.sonar.application.process; | |||
import java.io.InputStream; | |||
import java.util.concurrent.TimeUnit; | |||
public interface ProcessMonitor { | |||
public interface ManagedProcess { | |||
/** | |||
* @see Process#getInputStream() |
@@ -22,7 +22,7 @@ package org.sonar.application.process; | |||
import org.sonar.process.ProcessId; | |||
@FunctionalInterface | |||
public interface ProcessEventListener { | |||
public interface ManagedProcessEventListener { | |||
enum Type { | |||
OPERATIONAL, | |||
@@ -33,11 +33,11 @@ public interface ProcessEventListener { | |||
* This method is called when the process with the specified {@link ProcessId} | |||
* sends the event through the ipc shared memory. | |||
* Note that there can be a delay since the instant the process sets the flag | |||
* (see {@link SQProcess#WATCHER_DELAY_MS}). | |||
* (see {@link ManagedProcessHandler#WATCHER_DELAY_MS}). | |||
* | |||
* Call blocks the process watcher. Implementations should be asynchronous and | |||
* fork a new thread if call can be long. | |||
*/ | |||
void onProcessEvent(ProcessId processId, Type type); | |||
void onManagedProcessEvent(ProcessId processId, Type type); | |||
} |
@@ -32,18 +32,18 @@ import org.sonar.process.ProcessId; | |||
import static java.lang.String.format; | |||
import static java.util.Objects.requireNonNull; | |||
public class SQProcess { | |||
public class ManagedProcessHandler { | |||
public static final long DEFAULT_WATCHER_DELAY_MS = 500L; | |||
private static final Logger LOG = LoggerFactory.getLogger(SQProcess.class); | |||
private static final Logger LOG = LoggerFactory.getLogger(ManagedProcessHandler.class); | |||
private final ProcessId processId; | |||
private final Lifecycle lifecycle; | |||
private final List<ProcessEventListener> eventListeners; | |||
private final ManagedProcessLifecycle lifecycle; | |||
private final List<ManagedProcessEventListener> eventListeners; | |||
private final Timeout hardStopTimeout; | |||
private final long watcherDelayMs; | |||
private ProcessMonitor process; | |||
private ManagedProcess process; | |||
private StreamGobbler stdOutGobbler; | |||
private StreamGobbler stdErrGobbler; | |||
private final StopWatcher stopWatcher; | |||
@@ -52,9 +52,9 @@ public class SQProcess { | |||
// to listeners | |||
private final AtomicBoolean operational = new AtomicBoolean(false); | |||
private SQProcess(Builder builder) { | |||
private ManagedProcessHandler(Builder builder) { | |||
this.processId = requireNonNull(builder.processId, "processId can't be null"); | |||
this.lifecycle = new Lifecycle(this.processId, builder.lifecycleListeners); | |||
this.lifecycle = new ManagedProcessLifecycle(this.processId, builder.lifecycleListeners); | |||
this.eventListeners = builder.eventListeners; | |||
this.hardStopTimeout = builder.hardStopTimeout; | |||
this.watcherDelayMs = builder.watcherDelayMs; | |||
@@ -62,8 +62,8 @@ public class SQProcess { | |||
this.eventWatcher = new EventWatcher(); | |||
} | |||
public boolean start(Supplier<ProcessMonitor> commandLauncher) { | |||
if (!lifecycle.tryToMoveTo(Lifecycle.State.STARTING)) { | |||
public boolean start(Supplier<ManagedProcess> commandLauncher) { | |||
if (!lifecycle.tryToMoveTo(ManagedProcessLifecycle.State.STARTING)) { | |||
// has already been started | |||
return false; | |||
} | |||
@@ -71,7 +71,7 @@ public class SQProcess { | |||
this.process = commandLauncher.get(); | |||
} catch (RuntimeException e) { | |||
LOG.error("Fail to launch process [{}]", processId.getKey(), e); | |||
lifecycle.tryToMoveTo(Lifecycle.State.STOPPED); | |||
lifecycle.tryToMoveTo(ManagedProcessLifecycle.State.STOPPED); | |||
throw e; | |||
} | |||
this.stdOutGobbler = new StreamGobbler(process.getInputStream(), processId.getKey()); | |||
@@ -82,7 +82,7 @@ public class SQProcess { | |||
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); | |||
lifecycle.tryToMoveTo(ManagedProcessLifecycle.State.STARTED); | |||
return true; | |||
} | |||
@@ -90,7 +90,7 @@ public class SQProcess { | |||
return processId; | |||
} | |||
Lifecycle.State getState() { | |||
ManagedProcessLifecycle.State getState() { | |||
return lifecycle.getState(); | |||
} | |||
@@ -99,7 +99,7 @@ public class SQProcess { | |||
* executed). It depends on OS. | |||
*/ | |||
public void hardStop() { | |||
if (lifecycle.tryToMoveTo(Lifecycle.State.HARD_STOPPING)) { | |||
if (lifecycle.tryToMoveTo(ManagedProcessLifecycle.State.HARD_STOPPING)) { | |||
hardStopImpl(); | |||
if (process != null && process.isAlive()) { | |||
LOG.info("{} failed to stop in a quick fashion. Killing it.", processId.getKey()); | |||
@@ -155,18 +155,18 @@ public class SQProcess { | |||
StreamGobbler.waitUntilFinish(stdErrGobbler); | |||
stdErrGobbler.interrupt(); | |||
} | |||
lifecycle.tryToMoveTo(Lifecycle.State.STOPPED); | |||
lifecycle.tryToMoveTo(ManagedProcessLifecycle.State.STOPPED); | |||
} | |||
void refreshState() { | |||
if (process.isAlive()) { | |||
if (!operational.get() && process.isOperational()) { | |||
operational.set(true); | |||
eventListeners.forEach(l -> l.onProcessEvent(processId, ProcessEventListener.Type.OPERATIONAL)); | |||
eventListeners.forEach(l -> l.onManagedProcessEvent(processId, ManagedProcessEventListener.Type.OPERATIONAL)); | |||
} | |||
if (process.askedForRestart()) { | |||
process.acknowledgeAskForRestart(); | |||
eventListeners.forEach(l -> l.onProcessEvent(processId, ProcessEventListener.Type.ASK_FOR_RESTART)); | |||
eventListeners.forEach(l -> l.onManagedProcessEvent(processId, ManagedProcessEventListener.Type.ASK_FOR_RESTART)); | |||
} | |||
} else { | |||
stopForcibly(); | |||
@@ -237,7 +237,7 @@ public class SQProcess { | |||
public static class Builder { | |||
private final ProcessId processId; | |||
private final List<ProcessEventListener> eventListeners = new ArrayList<>(); | |||
private final List<ManagedProcessEventListener> eventListeners = new ArrayList<>(); | |||
private final List<ProcessLifecycleListener> lifecycleListeners = new ArrayList<>(); | |||
private long watcherDelayMs = DEFAULT_WATCHER_DELAY_MS; | |||
private Timeout hardStopTimeout = new Timeout(1, TimeUnit.MINUTES); | |||
@@ -246,7 +246,7 @@ public class SQProcess { | |||
this.processId = processId; | |||
} | |||
public Builder addEventListener(ProcessEventListener listener) { | |||
public Builder addEventListener(ManagedProcessEventListener listener) { | |||
this.eventListeners.add(listener); | |||
return this; | |||
} | |||
@@ -269,8 +269,8 @@ public class SQProcess { | |||
return this; | |||
} | |||
public SQProcess build() { | |||
return new SQProcess(this); | |||
public ManagedProcessHandler build() { | |||
return new ManagedProcessHandler(this); | |||
} | |||
} | |||
@@ -30,30 +30,30 @@ import org.slf4j.Logger; | |||
import org.slf4j.LoggerFactory; | |||
import org.sonar.process.ProcessId; | |||
import static org.sonar.application.process.Lifecycle.State.INIT; | |||
import static org.sonar.application.process.Lifecycle.State.STARTED; | |||
import static org.sonar.application.process.Lifecycle.State.STARTING; | |||
import static org.sonar.application.process.Lifecycle.State.STOPPED; | |||
import static org.sonar.application.process.Lifecycle.State.HARD_STOPPING; | |||
import static org.sonar.application.process.ManagedProcessLifecycle.State.INIT; | |||
import static org.sonar.application.process.ManagedProcessLifecycle.State.STARTED; | |||
import static org.sonar.application.process.ManagedProcessLifecycle.State.STARTING; | |||
import static org.sonar.application.process.ManagedProcessLifecycle.State.STOPPED; | |||
import static org.sonar.application.process.ManagedProcessLifecycle.State.HARD_STOPPING; | |||
public class Lifecycle { | |||
public class ManagedProcessLifecycle { | |||
public enum State { | |||
INIT, STARTING, STARTED, HARD_STOPPING, STOPPED | |||
} | |||
private static final Logger LOG = LoggerFactory.getLogger(Lifecycle.class); | |||
private static final Logger LOG = LoggerFactory.getLogger(ManagedProcessLifecycle.class); | |||
private static final Map<State, Set<State>> TRANSITIONS = buildTransitions(); | |||
private final ProcessId processId; | |||
private final List<ProcessLifecycleListener> listeners; | |||
private State state; | |||
public Lifecycle(ProcessId processId, List<ProcessLifecycleListener> listeners) { | |||
public ManagedProcessLifecycle(ProcessId processId, List<ProcessLifecycleListener> listeners) { | |||
this(processId, listeners, INIT); | |||
} | |||
Lifecycle(ProcessId processId, List<ProcessLifecycleListener> listeners, State initialState) { | |||
ManagedProcessLifecycle(ProcessId processId, List<ProcessLifecycleListener> listeners, State initialState) { | |||
this.processId = processId; | |||
this.listeners = listeners; | |||
this.state = initialState; |
@@ -24,11 +24,11 @@ import org.sonar.process.sharedmemoryfile.ProcessCommands; | |||
import static java.util.Objects.requireNonNull; | |||
class ProcessCommandsProcessMonitor extends AbstractProcessMonitor { | |||
public class ProcessCommandsManagedProcess extends AbstractManagedProcess { | |||
private final ProcessCommands commands; | |||
ProcessCommandsProcessMonitor(Process process, ProcessId processId, ProcessCommands commands) { | |||
public ProcessCommandsManagedProcess(Process process, ProcessId processId, ProcessCommands commands) { | |||
super(process, processId); | |||
this.commands = requireNonNull(commands, "commands can't be null"); | |||
} |
@@ -31,6 +31,6 @@ public interface ProcessLifecycleListener { | |||
* Call blocks the process watcher. Implementations should be asynchronous and | |||
* fork a new thread if call can be long. | |||
*/ | |||
void onProcessState(ProcessId processId, Lifecycle.State state); | |||
void onProcessState(ProcessId processId, ManagedProcessLifecycle.State state); | |||
} |
@@ -17,7 +17,7 @@ | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.application.process; | |||
package org.sonar.application; | |||
import java.io.IOException; | |||
import org.junit.Rule; | |||
@@ -26,7 +26,6 @@ import org.junit.rules.DisableOnDebug; | |||
import org.junit.rules.TemporaryFolder; | |||
import org.junit.rules.TestRule; | |||
import org.junit.rules.Timeout; | |||
import org.sonar.application.FileSystem; | |||
import org.sonar.application.config.AppSettings; | |||
import org.sonar.process.sharedmemoryfile.ProcessCommands; | |||
@@ -17,7 +17,7 @@ | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.application.process; | |||
package org.sonar.application; | |||
import java.io.File; | |||
import java.io.FileReader; | |||
@@ -36,6 +36,7 @@ import org.sonar.application.command.JavaCommand; | |||
import org.sonar.application.command.JvmOptions; | |||
import org.sonar.application.es.EsInstallation; | |||
import org.sonar.application.es.EsYmlSettings; | |||
import org.sonar.application.process.ManagedProcess; | |||
import org.sonar.process.ProcessId; | |||
import org.sonar.process.Props; | |||
import org.sonar.process.sharedmemoryfile.AllProcessesCommands; | |||
@@ -71,7 +72,7 @@ public class ProcessLauncherImplTest { | |||
.add("-Dfoo2=bar2")); | |||
command.setEsInstallation(createEsInstallation()); | |||
ProcessMonitor monitor = underTest.launch(command); | |||
ManagedProcess monitor = underTest.launch(command); | |||
assertThat(monitor).isNotNull(); | |||
assertThat(processBuilder.started).isTrue(); |
@@ -42,8 +42,7 @@ import org.sonar.application.command.CommandFactory; | |||
import org.sonar.application.command.EsScriptCommand; | |||
import org.sonar.application.command.JavaCommand; | |||
import org.sonar.application.config.TestAppSettings; | |||
import org.sonar.application.process.ProcessLauncher; | |||
import org.sonar.application.process.ProcessMonitor; | |||
import org.sonar.application.process.ManagedProcess; | |||
import org.sonar.process.ProcessId; | |||
import org.sonar.process.cluster.hz.HazelcastMember; | |||
@@ -104,14 +103,14 @@ public class SchedulerImplTest { | |||
underTest.schedule(); | |||
// elasticsearch does not have preconditions to start | |||
TestProcess es = processLauncher.waitForProcess(ELASTICSEARCH); | |||
TestManagedProcess es = processLauncher.waitForProcess(ELASTICSEARCH); | |||
assertThat(es.isAlive()).isTrue(); | |||
assertThat(processLauncher.processes).hasSize(1); | |||
// elasticsearch becomes operational -> web leader is starting | |||
es.operational = true; | |||
waitForAppStateOperational(appState, ELASTICSEARCH); | |||
TestProcess web = processLauncher.waitForProcess(WEB_SERVER); | |||
TestManagedProcess web = processLauncher.waitForProcess(WEB_SERVER); | |||
assertThat(web.isAlive()).isTrue(); | |||
assertThat(processLauncher.processes).hasSize(2); | |||
assertThat(processLauncher.commands).containsExactly(esScriptCommand, webLeaderCommand); | |||
@@ -119,7 +118,7 @@ public class SchedulerImplTest { | |||
// web becomes operational -> CE is starting | |||
web.operational = true; | |||
waitForAppStateOperational(appState, WEB_SERVER); | |||
TestProcess ce = processLauncher.waitForProcess(COMPUTE_ENGINE); | |||
TestManagedProcess ce = processLauncher.waitForProcess(COMPUTE_ENGINE); | |||
assertThat(ce.isAlive()).isTrue(); | |||
assertThat(processLauncher.processes).hasSize(3); | |||
assertThat(processLauncher.commands).containsExactly(esScriptCommand, webLeaderCommand, ceCommand); | |||
@@ -229,7 +228,7 @@ public class SchedulerImplTest { | |||
SchedulerImpl underTest = newScheduler(true); | |||
underTest.schedule(); | |||
TestProcess web = processLauncher.waitForProcessAlive(WEB_SERVER); | |||
TestManagedProcess web = processLauncher.waitForProcessAlive(WEB_SERVER); | |||
web.operational = true; | |||
processLauncher.waitForProcessAlive(COMPUTE_ENGINE); | |||
assertThat(processLauncher.processes).hasSize(2); | |||
@@ -342,28 +341,28 @@ public class SchedulerImplTest { | |||
} | |||
private class TestProcessLauncher implements ProcessLauncher { | |||
private final EnumMap<ProcessId, TestProcess> processes = new EnumMap<>(ProcessId.class); | |||
private final EnumMap<ProcessId, TestManagedProcess> processes = new EnumMap<>(ProcessId.class); | |||
private final List<AbstractCommand<?>> commands = synchronizedList(new ArrayList<>()); | |||
private ProcessId makeStartupFail = null; | |||
@Override | |||
public ProcessMonitor launch(AbstractCommand command) { | |||
public ManagedProcess launch(AbstractCommand command) { | |||
return launchImpl(command); | |||
} | |||
private ProcessMonitor launchImpl(AbstractCommand<?> javaCommand) { | |||
private ManagedProcess launchImpl(AbstractCommand<?> javaCommand) { | |||
commands.add(javaCommand); | |||
if (makeStartupFail == javaCommand.getProcessId()) { | |||
throw new IllegalStateException("cannot start " + javaCommand.getProcessId()); | |||
} | |||
TestProcess process = new TestProcess(javaCommand.getProcessId()); | |||
TestManagedProcess process = new TestManagedProcess(javaCommand.getProcessId()); | |||
processes.put(javaCommand.getProcessId(), process); | |||
return process; | |||
} | |||
private TestProcess waitForProcess(ProcessId id) throws InterruptedException { | |||
private TestManagedProcess waitForProcess(ProcessId id) throws InterruptedException { | |||
while (true) { | |||
TestProcess p = processes.get(id); | |||
TestManagedProcess p = processes.get(id); | |||
if (p != null) { | |||
return p; | |||
} | |||
@@ -371,9 +370,9 @@ public class SchedulerImplTest { | |||
} | |||
} | |||
private TestProcess waitForProcessAlive(ProcessId id) throws InterruptedException { | |||
private TestManagedProcess waitForProcessAlive(ProcessId id) throws InterruptedException { | |||
while (true) { | |||
TestProcess p = processes.get(id); | |||
TestManagedProcess p = processes.get(id); | |||
if (p != null && p.isAlive()) { | |||
return p; | |||
} | |||
@@ -381,9 +380,9 @@ public class SchedulerImplTest { | |||
} | |||
} | |||
private TestProcess waitForProcessDown(ProcessId id) throws InterruptedException { | |||
private TestManagedProcess waitForProcessDown(ProcessId id) throws InterruptedException { | |||
while (true) { | |||
TestProcess p = processes.get(id); | |||
TestManagedProcess p = processes.get(id); | |||
if (p != null && !p.isAlive()) { | |||
return p; | |||
} | |||
@@ -393,19 +392,19 @@ public class SchedulerImplTest { | |||
@Override | |||
public void close() { | |||
for (TestProcess process : processes.values()) { | |||
for (TestManagedProcess process : processes.values()) { | |||
process.destroyForcibly(); | |||
} | |||
} | |||
} | |||
private class TestProcess implements ProcessMonitor, AutoCloseable { | |||
private class TestManagedProcess implements ManagedProcess, AutoCloseable { | |||
private final ProcessId processId; | |||
private final CountDownLatch alive = new CountDownLatch(1); | |||
private boolean operational = false; | |||
private boolean askedForRestart = false; | |||
private TestProcess(ProcessId processId) { | |||
private TestManagedProcess(ProcessId processId) { | |||
this.processId = processId; | |||
} | |||
@@ -38,13 +38,13 @@ import static org.assertj.core.api.Assertions.tuple; | |||
import static org.mockito.Mockito.mock; | |||
import static org.mockito.Mockito.when; | |||
public class EsProcessMonitorTest { | |||
public class EsManagedProcessTest { | |||
@Test | |||
public void isOperational_should_return_false_if_Elasticsearch_is_RED() { | |||
EsConnector esConnector = mock(EsConnector.class); | |||
when(esConnector.getClusterHealthStatus()).thenReturn(ClusterHealthStatus.RED); | |||
EsProcessMonitor underTest = new EsProcessMonitor(mock(Process.class), ProcessId.ELASTICSEARCH, esConnector); | |||
EsManagedProcess underTest = new EsManagedProcess(mock(Process.class), ProcessId.ELASTICSEARCH, esConnector); | |||
assertThat(underTest.isOperational()).isFalse(); | |||
} | |||
@@ -52,7 +52,7 @@ public class EsProcessMonitorTest { | |||
public void isOperational_should_return_true_if_Elasticsearch_is_YELLOW() { | |||
EsConnector esConnector = mock(EsConnector.class); | |||
when(esConnector.getClusterHealthStatus()).thenReturn(ClusterHealthStatus.YELLOW); | |||
EsProcessMonitor underTest = new EsProcessMonitor(mock(Process.class), ProcessId.ELASTICSEARCH, esConnector); | |||
EsManagedProcess underTest = new EsManagedProcess(mock(Process.class), ProcessId.ELASTICSEARCH, esConnector); | |||
assertThat(underTest.isOperational()).isTrue(); | |||
} | |||
@@ -60,7 +60,7 @@ public class EsProcessMonitorTest { | |||
public void isOperational_should_return_true_if_Elasticsearch_is_GREEN() { | |||
EsConnector esConnector = mock(EsConnector.class); | |||
when(esConnector.getClusterHealthStatus()).thenReturn(ClusterHealthStatus.GREEN); | |||
EsProcessMonitor underTest = new EsProcessMonitor(mock(Process.class), ProcessId.ELASTICSEARCH, esConnector); | |||
EsManagedProcess underTest = new EsManagedProcess(mock(Process.class), ProcessId.ELASTICSEARCH, esConnector); | |||
assertThat(underTest.isOperational()).isTrue(); | |||
} | |||
@@ -68,7 +68,7 @@ public class EsProcessMonitorTest { | |||
public void isOperational_should_return_true_if_Elasticsearch_was_GREEN_once() { | |||
EsConnector esConnector = mock(EsConnector.class); | |||
when(esConnector.getClusterHealthStatus()).thenReturn(ClusterHealthStatus.GREEN); | |||
EsProcessMonitor underTest = new EsProcessMonitor(mock(Process.class), ProcessId.ELASTICSEARCH, esConnector); | |||
EsManagedProcess underTest = new EsManagedProcess(mock(Process.class), ProcessId.ELASTICSEARCH, esConnector); | |||
assertThat(underTest.isOperational()).isTrue(); | |||
when(esConnector.getClusterHealthStatus()).thenReturn(ClusterHealthStatus.RED); | |||
@@ -81,7 +81,7 @@ public class EsProcessMonitorTest { | |||
when(esConnector.getClusterHealthStatus()) | |||
.thenThrow(new NoNodeAvailableException("test")) | |||
.thenReturn(ClusterHealthStatus.GREEN); | |||
EsProcessMonitor underTest = new EsProcessMonitor(mock(Process.class), ProcessId.ELASTICSEARCH, esConnector); | |||
EsManagedProcess underTest = new EsManagedProcess(mock(Process.class), ProcessId.ELASTICSEARCH, esConnector); | |||
assertThat(underTest.isOperational()).isTrue(); | |||
} | |||
@@ -90,7 +90,7 @@ public class EsProcessMonitorTest { | |||
EsConnector esConnector = mock(EsConnector.class); | |||
when(esConnector.getClusterHealthStatus()) | |||
.thenThrow(new RuntimeException("test")); | |||
EsProcessMonitor underTest = new EsProcessMonitor(mock(Process.class), ProcessId.ELASTICSEARCH, esConnector); | |||
EsManagedProcess underTest = new EsManagedProcess(mock(Process.class), ProcessId.ELASTICSEARCH, esConnector); | |||
assertThat(underTest.isOperational()).isFalse(); | |||
} | |||
@@ -101,13 +101,13 @@ public class EsProcessMonitorTest { | |||
lc.reset(); | |||
memoryAppender.setContext(lc); | |||
memoryAppender.start(); | |||
lc.getLogger(EsProcessMonitor.class).addAppender(memoryAppender); | |||
lc.getLogger(EsManagedProcess.class).addAppender(memoryAppender); | |||
EsConnector esConnector = mock(EsConnector.class); | |||
when(esConnector.getClusterHealthStatus()) | |||
.thenThrow(new MasterNotDiscoveredException("Master not elected -test-")); | |||
EsProcessMonitor underTest = new EsProcessMonitor(mock(Process.class), ProcessId.ELASTICSEARCH, esConnector); | |||
EsManagedProcess underTest = new EsManagedProcess(mock(Process.class), ProcessId.ELASTICSEARCH, esConnector); | |||
assertThat(underTest.isOperational()).isFalse(); | |||
assertThat(memoryAppender.events).isNotEmpty(); | |||
assertThat(memoryAppender.events) |
@@ -36,9 +36,9 @@ import static org.mockito.Mockito.mock; | |||
import static org.mockito.Mockito.timeout; | |||
import static org.mockito.Mockito.verify; | |||
import static org.mockito.Mockito.verifyNoMoreInteractions; | |||
import static org.sonar.application.process.SQProcess.Timeout.newTimeout; | |||
import static org.sonar.application.process.ManagedProcessHandler.Timeout.newTimeout; | |||
public class SQProcessTest { | |||
public class ManagedProcessHandlerTest { | |||
private static final ProcessId A_PROCESS_ID = ProcessId.ELASTICSEARCH; | |||
@@ -49,91 +49,91 @@ public class SQProcessTest { | |||
@Test | |||
public void initial_state_is_INIT() { | |||
SQProcess underTest = SQProcess.builder(A_PROCESS_ID).build(); | |||
ManagedProcessHandler underTest = ManagedProcessHandler.builder(A_PROCESS_ID).build(); | |||
assertThat(underTest.getProcessId()).isEqualTo(A_PROCESS_ID); | |||
assertThat(underTest.getState()).isEqualTo(Lifecycle.State.INIT); | |||
assertThat(underTest.getState()).isEqualTo(ManagedProcessLifecycle.State.INIT); | |||
} | |||
@Test | |||
public void start_and_stop_process() { | |||
ProcessLifecycleListener listener = mock(ProcessLifecycleListener.class); | |||
SQProcess underTest = SQProcess.builder(A_PROCESS_ID) | |||
ManagedProcessHandler underTest = ManagedProcessHandler.builder(A_PROCESS_ID) | |||
.addProcessLifecycleListener(listener) | |||
.build(); | |||
try (TestProcess testProcess = new TestProcess()) { | |||
try (TestManagedProcess testProcess = new TestManagedProcess()) { | |||
assertThat(underTest.start(() -> testProcess)).isTrue(); | |||
assertThat(underTest.getState()).isEqualTo(Lifecycle.State.STARTED); | |||
assertThat(underTest.getState()).isEqualTo(ManagedProcessLifecycle.State.STARTED); | |||
assertThat(testProcess.isAlive()).isTrue(); | |||
assertThat(testProcess.streamsClosed).isFalse(); | |||
verify(listener).onProcessState(A_PROCESS_ID, Lifecycle.State.STARTED); | |||
verify(listener).onProcessState(A_PROCESS_ID, ManagedProcessLifecycle.State.STARTED); | |||
testProcess.close(); | |||
// do not wait next run of watcher threads | |||
underTest.refreshState(); | |||
assertThat(underTest.getState()).isEqualTo(Lifecycle.State.STOPPED); | |||
assertThat(underTest.getState()).isEqualTo(ManagedProcessLifecycle.State.STOPPED); | |||
assertThat(testProcess.isAlive()).isFalse(); | |||
assertThat(testProcess.streamsClosed).isTrue(); | |||
verify(listener).onProcessState(A_PROCESS_ID, Lifecycle.State.STOPPED); | |||
verify(listener).onProcessState(A_PROCESS_ID, ManagedProcessLifecycle.State.STOPPED); | |||
} | |||
} | |||
@Test | |||
public void start_does_not_nothing_if_already_started_once() { | |||
SQProcess underTest = SQProcess.builder(A_PROCESS_ID).build(); | |||
ManagedProcessHandler underTest = ManagedProcessHandler.builder(A_PROCESS_ID).build(); | |||
try (TestProcess testProcess = new TestProcess()) { | |||
try (TestManagedProcess testProcess = new TestManagedProcess()) { | |||
assertThat(underTest.start(() -> testProcess)).isTrue(); | |||
assertThat(underTest.getState()).isEqualTo(Lifecycle.State.STARTED); | |||
assertThat(underTest.getState()).isEqualTo(ManagedProcessLifecycle.State.STARTED); | |||
assertThat(underTest.start(() -> {throw new IllegalStateException();})).isFalse(); | |||
assertThat(underTest.getState()).isEqualTo(Lifecycle.State.STARTED); | |||
assertThat(underTest.getState()).isEqualTo(ManagedProcessLifecycle.State.STARTED); | |||
} | |||
} | |||
@Test | |||
public void start_throws_exception_and_move_to_state_STOPPED_if_execution_of_command_fails() { | |||
SQProcess underTest = SQProcess.builder(A_PROCESS_ID).build(); | |||
ManagedProcessHandler underTest = ManagedProcessHandler.builder(A_PROCESS_ID).build(); | |||
expectedException.expect(IllegalStateException.class); | |||
expectedException.expectMessage("error"); | |||
underTest.start(() -> {throw new IllegalStateException("error");}); | |||
assertThat(underTest.getState()).isEqualTo(Lifecycle.State.STOPPED); | |||
assertThat(underTest.getState()).isEqualTo(ManagedProcessLifecycle.State.STOPPED); | |||
} | |||
@Test | |||
public void send_event_when_process_is_operational() { | |||
ProcessEventListener listener = mock(ProcessEventListener.class); | |||
SQProcess underTest = SQProcess.builder(A_PROCESS_ID) | |||
ManagedProcessEventListener listener = mock(ManagedProcessEventListener.class); | |||
ManagedProcessHandler underTest = ManagedProcessHandler.builder(A_PROCESS_ID) | |||
.addEventListener(listener) | |||
.build(); | |||
try (TestProcess testProcess = new TestProcess()) { | |||
try (TestManagedProcess testProcess = new TestManagedProcess()) { | |||
underTest.start(() -> testProcess); | |||
testProcess.operational = true; | |||
underTest.refreshState(); | |||
verify(listener).onProcessEvent(A_PROCESS_ID, ProcessEventListener.Type.OPERATIONAL); | |||
verify(listener).onManagedProcessEvent(A_PROCESS_ID, ManagedProcessEventListener.Type.OPERATIONAL); | |||
} | |||
verifyNoMoreInteractions(listener); | |||
} | |||
@Test | |||
public void operational_event_is_sent_once() { | |||
ProcessEventListener listener = mock(ProcessEventListener.class); | |||
SQProcess underTest = SQProcess.builder(A_PROCESS_ID) | |||
ManagedProcessEventListener listener = mock(ManagedProcessEventListener.class); | |||
ManagedProcessHandler underTest = ManagedProcessHandler.builder(A_PROCESS_ID) | |||
.addEventListener(listener) | |||
.build(); | |||
try (TestProcess testProcess = new TestProcess()) { | |||
try (TestManagedProcess testProcess = new TestManagedProcess()) { | |||
underTest.start(() -> testProcess); | |||
testProcess.operational = true; | |||
underTest.refreshState(); | |||
verify(listener).onProcessEvent(A_PROCESS_ID, ProcessEventListener.Type.OPERATIONAL); | |||
verify(listener).onManagedProcessEvent(A_PROCESS_ID, ManagedProcessEventListener.Type.OPERATIONAL); | |||
// second run | |||
underTest.refreshState(); | |||
@@ -143,17 +143,17 @@ public class SQProcessTest { | |||
@Test | |||
public void send_event_when_process_requests_for_restart() { | |||
ProcessEventListener listener = mock(ProcessEventListener.class); | |||
SQProcess underTest = SQProcess.builder(A_PROCESS_ID) | |||
ManagedProcessEventListener listener = mock(ManagedProcessEventListener.class); | |||
ManagedProcessHandler underTest = ManagedProcessHandler.builder(A_PROCESS_ID) | |||
.addEventListener(listener) | |||
.setWatcherDelayMs(1L) | |||
.build(); | |||
try (TestProcess testProcess = new TestProcess()) { | |||
try (TestManagedProcess testProcess = new TestManagedProcess()) { | |||
underTest.start(() -> testProcess); | |||
testProcess.askedForRestart = true; | |||
verify(listener, timeout(10_000)).onProcessEvent(A_PROCESS_ID, ProcessEventListener.Type.ASK_FOR_RESTART); | |||
verify(listener, timeout(10_000)).onManagedProcessEvent(A_PROCESS_ID, ManagedProcessEventListener.Type.ASK_FOR_RESTART); | |||
// flag is reset so that next run does not trigger again the event | |||
underTest.refreshState(); | |||
@@ -164,31 +164,31 @@ public class SQProcessTest { | |||
@Test | |||
public void stopForcibly_stops_the_process_without_graceful_request_for_stop() { | |||
SQProcess underTest = SQProcess.builder(A_PROCESS_ID).build(); | |||
ManagedProcessHandler underTest = ManagedProcessHandler.builder(A_PROCESS_ID).build(); | |||
try (TestProcess testProcess = new TestProcess()) { | |||
try (TestManagedProcess testProcess = new TestManagedProcess()) { | |||
underTest.start(() -> testProcess); | |||
underTest.stopForcibly(); | |||
assertThat(underTest.getState()).isEqualTo(Lifecycle.State.STOPPED); | |||
assertThat(underTest.getState()).isEqualTo(ManagedProcessLifecycle.State.STOPPED); | |||
assertThat(testProcess.askedForHardStop).isFalse(); | |||
assertThat(testProcess.destroyedForcibly).isTrue(); | |||
// second execution of stopForcibly does nothing. It's still stopped. | |||
underTest.stopForcibly(); | |||
assertThat(underTest.getState()).isEqualTo(Lifecycle.State.STOPPED); | |||
assertThat(underTest.getState()).isEqualTo(ManagedProcessLifecycle.State.STOPPED); | |||
} | |||
} | |||
@Test | |||
public void process_stops_after_graceful_request_for_stop() throws Exception { | |||
ProcessLifecycleListener listener = mock(ProcessLifecycleListener.class); | |||
SQProcess underTest = SQProcess.builder(A_PROCESS_ID) | |||
ManagedProcessHandler underTest = ManagedProcessHandler.builder(A_PROCESS_ID) | |||
.addProcessLifecycleListener(listener) | |||
.setHardStopTimeout(newTimeout(1, TimeUnit.HOURS)) | |||
.build(); | |||
try (TestProcess testProcess = new TestProcess()) { | |||
try (TestManagedProcess testProcess = new TestManagedProcess()) { | |||
underTest.start(() -> testProcess); | |||
Thread stopperThread = new Thread(underTest::hardStop); | |||
@@ -201,8 +201,8 @@ public class SQProcessTest { | |||
while (!testProcess.askedForHardStop) { | |||
Thread.sleep(1L); | |||
} | |||
assertThat(underTest.getState()).isEqualTo(Lifecycle.State.HARD_STOPPING); | |||
verify(listener).onProcessState(A_PROCESS_ID, Lifecycle.State.HARD_STOPPING); | |||
assertThat(underTest.getState()).isEqualTo(ManagedProcessLifecycle.State.HARD_STOPPING); | |||
verify(listener).onProcessState(A_PROCESS_ID, ManagedProcessLifecycle.State.HARD_STOPPING); | |||
// process stopped | |||
testProcess.close(); | |||
@@ -210,20 +210,20 @@ public class SQProcessTest { | |||
// waiting for stopper thread to detect and handle the stop | |||
stopperThread.join(); | |||
assertThat(underTest.getState()).isEqualTo(Lifecycle.State.STOPPED); | |||
verify(listener).onProcessState(A_PROCESS_ID, Lifecycle.State.STOPPED); | |||
assertThat(underTest.getState()).isEqualTo(ManagedProcessLifecycle.State.STOPPED); | |||
verify(listener).onProcessState(A_PROCESS_ID, ManagedProcessLifecycle.State.STOPPED); | |||
} | |||
} | |||
@Test | |||
public void process_is_stopped_forcibly_if_graceful_stop_is_too_long() throws Exception { | |||
ProcessLifecycleListener listener = mock(ProcessLifecycleListener.class); | |||
SQProcess underTest = SQProcess.builder(A_PROCESS_ID) | |||
ManagedProcessHandler underTest = ManagedProcessHandler.builder(A_PROCESS_ID) | |||
.addProcessLifecycleListener(listener) | |||
.setHardStopTimeout(newTimeout(1, TimeUnit.MILLISECONDS)) | |||
.build(); | |||
try (TestProcess testProcess = new TestProcess()) { | |||
try (TestManagedProcess testProcess = new TestManagedProcess()) { | |||
underTest.start(() -> testProcess); | |||
underTest.hardStop(); | |||
@@ -232,35 +232,35 @@ public class SQProcessTest { | |||
assertThat(testProcess.askedForHardStop).isTrue(); | |||
assertThat(testProcess.destroyedForcibly).isTrue(); | |||
assertThat(testProcess.isAlive()).isFalse(); | |||
assertThat(underTest.getState()).isEqualTo(Lifecycle.State.STOPPED); | |||
verify(listener).onProcessState(A_PROCESS_ID, Lifecycle.State.STOPPED); | |||
assertThat(underTest.getState()).isEqualTo(ManagedProcessLifecycle.State.STOPPED); | |||
verify(listener).onProcessState(A_PROCESS_ID, ManagedProcessLifecycle.State.STOPPED); | |||
} | |||
} | |||
@Test | |||
public void process_requests_are_listened_on_regular_basis() { | |||
ProcessEventListener listener = mock(ProcessEventListener.class); | |||
SQProcess underTest = SQProcess.builder(A_PROCESS_ID) | |||
ManagedProcessEventListener listener = mock(ManagedProcessEventListener.class); | |||
ManagedProcessHandler underTest = ManagedProcessHandler.builder(A_PROCESS_ID) | |||
.addEventListener(listener) | |||
.setWatcherDelayMs(1L) | |||
.build(); | |||
try (TestProcess testProcess = new TestProcess()) { | |||
try (TestManagedProcess testProcess = new TestManagedProcess()) { | |||
underTest.start(() -> testProcess); | |||
testProcess.operational = true; | |||
verify(listener, timeout(1_000L)).onProcessEvent(A_PROCESS_ID, ProcessEventListener.Type.OPERATIONAL); | |||
verify(listener, timeout(1_000L)).onManagedProcessEvent(A_PROCESS_ID, ManagedProcessEventListener.Type.OPERATIONAL); | |||
} | |||
} | |||
@Test | |||
public void test_toString() { | |||
SQProcess underTest = SQProcess.builder(A_PROCESS_ID).build(); | |||
ManagedProcessHandler underTest = ManagedProcessHandler.builder(A_PROCESS_ID).build(); | |||
assertThat(underTest.toString()).isEqualTo("Process[" + A_PROCESS_ID.getKey() + "]"); | |||
} | |||
private static class TestProcess implements ProcessMonitor, AutoCloseable { | |||
private static class TestManagedProcess implements ManagedProcess, AutoCloseable { | |||
private final CountDownLatch alive = new CountDownLatch(1); | |||
private final InputStream inputStream = mock(InputStream.class, Mockito.RETURNS_MOCKS); |
@@ -28,23 +28,23 @@ import org.sonar.process.ProcessId; | |||
import static java.util.Arrays.asList; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
import static org.sonar.application.process.Lifecycle.State.INIT; | |||
import static org.sonar.application.process.Lifecycle.State.STARTED; | |||
import static org.sonar.application.process.Lifecycle.State.STARTING; | |||
import static org.sonar.application.process.Lifecycle.State.HARD_STOPPING; | |||
import static org.sonar.application.process.ManagedProcessLifecycle.State.INIT; | |||
import static org.sonar.application.process.ManagedProcessLifecycle.State.STARTED; | |||
import static org.sonar.application.process.ManagedProcessLifecycle.State.STARTING; | |||
import static org.sonar.application.process.ManagedProcessLifecycle.State.HARD_STOPPING; | |||
public class LifecycleTest { | |||
public class ManagedProcessLifecycleTest { | |||
@Test | |||
public void initial_state_is_INIT() { | |||
Lifecycle lifecycle = new Lifecycle(ProcessId.ELASTICSEARCH, Collections.emptyList()); | |||
ManagedProcessLifecycle lifecycle = new ManagedProcessLifecycle(ProcessId.ELASTICSEARCH, Collections.emptyList()); | |||
assertThat(lifecycle.getState()).isEqualTo(INIT); | |||
} | |||
@Test | |||
public void try_to_move_does_not_support_jumping_states() { | |||
TestLifeCycleListener listener = new TestLifeCycleListener(); | |||
Lifecycle lifecycle = new Lifecycle(ProcessId.ELASTICSEARCH, asList(listener)); | |||
ManagedProcessLifecycle lifecycle = new ManagedProcessLifecycle(ProcessId.ELASTICSEARCH, asList(listener)); | |||
assertThat(lifecycle.getState()).isEqualTo(INIT); | |||
assertThat(listener.states).isEmpty(); | |||
@@ -59,14 +59,14 @@ public class LifecycleTest { | |||
@Test | |||
public void no_state_can_not_move_to_itself() { | |||
for (Lifecycle.State state : Lifecycle.State.values()) { | |||
for (ManagedProcessLifecycle.State state : ManagedProcessLifecycle.State.values()) { | |||
assertThat(newLifeCycle(state).tryToMoveTo(state)).isFalse(); | |||
} | |||
} | |||
@Test | |||
public void can_move_to_STOPPING_from_STARTING_STARTED_only() { | |||
for (Lifecycle.State state : Lifecycle.State.values()) { | |||
for (ManagedProcessLifecycle.State state : ManagedProcessLifecycle.State.values()) { | |||
TestLifeCycleListener listener = new TestLifeCycleListener(); | |||
boolean tryToMoveTo = newLifeCycle(state, listener).tryToMoveTo(HARD_STOPPING); | |||
if (state == STARTING || state == STARTED) { | |||
@@ -81,7 +81,7 @@ public class LifecycleTest { | |||
@Test | |||
public void can_move_to_STARTED_from_STARTING_only() { | |||
for (Lifecycle.State state : Lifecycle.State.values()) { | |||
for (ManagedProcessLifecycle.State state : ManagedProcessLifecycle.State.values()) { | |||
TestLifeCycleListener listener = new TestLifeCycleListener(); | |||
boolean tryToMoveTo = newLifeCycle(state, listener).tryToMoveTo(STARTED); | |||
if (state == STARTING) { | |||
@@ -94,15 +94,15 @@ public class LifecycleTest { | |||
} | |||
} | |||
private static Lifecycle newLifeCycle(Lifecycle.State state, TestLifeCycleListener... listeners) { | |||
return new Lifecycle(ProcessId.ELASTICSEARCH, Arrays.asList(listeners), state); | |||
private static ManagedProcessLifecycle newLifeCycle(ManagedProcessLifecycle.State state, TestLifeCycleListener... listeners) { | |||
return new ManagedProcessLifecycle(ProcessId.ELASTICSEARCH, Arrays.asList(listeners), state); | |||
} | |||
private static final class TestLifeCycleListener implements ProcessLifecycleListener { | |||
private final List<Lifecycle.State> states = new ArrayList<>(); | |||
private final List<ManagedProcessLifecycle.State> states = new ArrayList<>(); | |||
@Override | |||
public void onProcessState(ProcessId processId, Lifecycle.State state) { | |||
public void onProcessState(ProcessId processId, ManagedProcessLifecycle.State state) { | |||
this.states.add(state); | |||
} | |||
} |
@@ -35,14 +35,14 @@ import static org.mockito.Mockito.verify; | |||
import static org.mockito.Mockito.when; | |||
public class ProcessCommandsProcessMonitorTest { | |||
public class ProcessCommandsManagedProcessTest { | |||
@Test | |||
public void ProcessMonitorImpl_is_a_proxy_of_Process() throws Exception { | |||
Process process = mock(Process.class, RETURNS_DEEP_STUBS); | |||
ProcessCommands commands = mock(ProcessCommands.class, RETURNS_DEEP_STUBS); | |||
ProcessCommandsProcessMonitor underTest = new ProcessCommandsProcessMonitor(process, ProcessId.WEB_SERVER, commands); | |||
ProcessCommandsManagedProcess underTest = new ProcessCommandsManagedProcess(process, ProcessId.WEB_SERVER, commands); | |||
underTest.waitFor(); | |||
verify(process).waitFor(); | |||
@@ -69,7 +69,7 @@ public class ProcessCommandsProcessMonitorTest { | |||
Process process = mock(Process.class, RETURNS_DEEP_STUBS); | |||
ProcessCommands commands = mock(ProcessCommands.class, RETURNS_DEEP_STUBS); | |||
ProcessCommandsProcessMonitor underTest = new ProcessCommandsProcessMonitor(process, null, commands); | |||
ProcessCommandsManagedProcess underTest = new ProcessCommandsManagedProcess(process, null, commands); | |||
underTest.askForHardStop(); | |||
verify(commands).askForHardStop(); | |||
@@ -90,7 +90,7 @@ public class ProcessCommandsProcessMonitorTest { | |||
Process process = mock(Process.class); | |||
when(process.getInputStream()).thenReturn(null); | |||
ProcessCommandsProcessMonitor underTest = new ProcessCommandsProcessMonitor(process, null, commands); | |||
ProcessCommandsManagedProcess underTest = new ProcessCommandsManagedProcess(process, null, commands); | |||
// no failures | |||
underTest.closeStreams(); | |||
@@ -103,7 +103,7 @@ public class ProcessCommandsProcessMonitorTest { | |||
Process process = mock(Process.class); | |||
when(process.getInputStream()).thenReturn(stream); | |||
ProcessCommandsProcessMonitor underTest = new ProcessCommandsProcessMonitor(process, null, mock(ProcessCommands.class, Mockito.RETURNS_MOCKS)); | |||
ProcessCommandsManagedProcess underTest = new ProcessCommandsManagedProcess(process, null, mock(ProcessCommands.class, Mockito.RETURNS_MOCKS)); | |||
// no failures | |||
underTest.closeStreams(); |
@@ -29,10 +29,6 @@ import org.sonar.application.command.JavaVersion; | |||
import org.sonar.application.config.AppSettings; | |||
import org.sonar.application.config.AppSettingsLoader; | |||
import org.sonar.application.config.AppSettingsLoaderImpl; | |||
import org.sonar.application.process.HardStopRequestWatcherImpl; | |||
import org.sonar.application.process.ProcessLauncher; | |||
import org.sonar.application.process.ProcessLauncherImpl; | |||
import org.sonar.application.process.StopRequestWatcher; | |||
import org.sonar.core.extension.ServiceLoaderWrapper; | |||
import org.sonar.process.System2; | |||
import org.sonar.process.SystemExit; |