diff options
author | Jenkins CI <ci@sonarsource.com> | 2014-09-22 17:59:10 +0200 |
---|---|---|
committer | Jenkins CI <ci@sonarsource.com> | 2014-09-22 17:59:10 +0200 |
commit | 5506038e6bebe3c0be5d7d3c099c4e6f73e315be (patch) | |
tree | 5e554ea1f9467b8060cbe075ce61d1ae3b97b501 /server/sonar-process-monitor | |
parent | 8a7965dfbc7c967e199d5cf4f4c83ff8dd81a6c3 (diff) | |
parent | 92c30ccd4cd311dc602c0e1a08fc97c09970a4f6 (diff) | |
download | sonarqube-5506038e6bebe3c0be5d7d3c099c4e6f73e315be.tar.gz sonarqube-5506038e6bebe3c0be5d7d3c099c4e6f73e315be.zip |
Automatic merge from branch-4.5
* origin/branch-4.5:
SONAR-4898 file-based inter-process communication
SONAR-4898 add info log
Diffstat (limited to 'server/sonar-process-monitor')
8 files changed, 68 insertions, 44 deletions
diff --git a/server/sonar-process-monitor/src/main/java/org/sonar/process/monitor/JavaCommand.java b/server/sonar-process-monitor/src/main/java/org/sonar/process/monitor/JavaCommand.java index 7920581a5a2..7750b6deb35 100644 --- a/server/sonar-process-monitor/src/main/java/org/sonar/process/monitor/JavaCommand.java +++ b/server/sonar-process-monitor/src/main/java/org/sonar/process/monitor/JavaCommand.java @@ -79,13 +79,6 @@ public class JavaCommand { return this; } - public File getReadyFile() { - if (tempDir == null) { - throw new IllegalStateException("Temp directory not set"); - } - return new File(tempDir, key + ".ready"); - } - public List<String> getJavaOptions() { return javaOptions; } diff --git a/server/sonar-process-monitor/src/main/java/org/sonar/process/monitor/JavaProcessLauncher.java b/server/sonar-process-monitor/src/main/java/org/sonar/process/monitor/JavaProcessLauncher.java index 0fa33bc9c37..0f2abc34b16 100644 --- a/server/sonar-process-monitor/src/main/java/org/sonar/process/monitor/JavaProcessLauncher.java +++ b/server/sonar-process-monitor/src/main/java/org/sonar/process/monitor/JavaProcessLauncher.java @@ -21,9 +21,9 @@ package org.sonar.process.monitor; import org.apache.commons.lang.StringUtils; import org.slf4j.LoggerFactory; +import org.sonar.process.ProcessCommands; import org.sonar.process.ProcessEntryPoint; import org.sonar.process.ProcessUtils; -import org.sonar.process.SharedStatus; import java.io.File; import java.io.FileOutputStream; @@ -46,8 +46,8 @@ public class JavaProcessLauncher { try { // cleanup existing monitor file. Child process creates it when ready. // TODO fail if impossible to delete - SharedStatus sharedStatus = new SharedStatus(command.getReadyFile()); - sharedStatus.prepare(); + ProcessCommands commands = new ProcessCommands(command.getTempDir(), command.getKey()); + commands.prepareMonitor(); ProcessBuilder processBuilder = create(command); LoggerFactory.getLogger(getClass()).info("Launch {}: {}", @@ -58,7 +58,7 @@ public class JavaProcessLauncher { StreamGobbler inputGobbler = new StreamGobbler(process.getInputStream(), command.getKey()); inputGobbler.start(); - ProcessRef ref = new ProcessRef(command.getKey(), sharedStatus, process, inputGobbler); + ProcessRef ref = new ProcessRef(command.getKey(), commands, process, inputGobbler); ref.setLaunchedAt(startedAt); return ref; @@ -105,7 +105,7 @@ public class JavaProcessLauncher { props.putAll(javaCommand.getArguments()); props.setProperty(ProcessEntryPoint.PROPERTY_PROCESS_KEY, javaCommand.getKey()); props.setProperty(ProcessEntryPoint.PROPERTY_TERMINATION_TIMEOUT, String.valueOf(timeouts.getTerminationTimeout())); - props.setProperty(ProcessEntryPoint.PROPERTY_STATUS_PATH, javaCommand.getReadyFile().getAbsolutePath()); + props.setProperty(ProcessEntryPoint.PROPERTY_SHARED_PATH, javaCommand.getTempDir().getAbsolutePath()); OutputStream out = new FileOutputStream(propertiesFile); props.store(out, String.format("Temporary properties file for command [%s]", javaCommand.getKey())); out.close(); diff --git a/server/sonar-process-monitor/src/main/java/org/sonar/process/monitor/Monitor.java b/server/sonar-process-monitor/src/main/java/org/sonar/process/monitor/Monitor.java index 86e47ca429e..45141afdc54 100644 --- a/server/sonar-process-monitor/src/main/java/org/sonar/process/monitor/Monitor.java +++ b/server/sonar-process-monitor/src/main/java/org/sonar/process/monitor/Monitor.java @@ -40,15 +40,15 @@ public class Monitor { // used by awaitStop() to block until all processes are shutdown private final List<WatcherThread> watcherThreads = new CopyOnWriteArrayList<WatcherThread>(); - Monitor(JavaProcessLauncher launcher, SystemExit exit) { + Monitor(JavaProcessLauncher launcher, SystemExit exit, TerminatorThread terminator) { this.launcher = launcher; - this.terminator = new TerminatorThread(processes); + this.terminator = terminator; this.systemExit = exit; } public static Monitor create() { Timeouts timeouts = new Timeouts(); - return new Monitor(new JavaProcessLauncher(timeouts), new SystemExit()); + return new Monitor(new JavaProcessLauncher(timeouts), new SystemExit(), new TerminatorThread(timeouts)); } /** @@ -143,6 +143,7 @@ public class Monitor { boolean requested = false; if (lifecycle.tryToMoveTo(State.STOPPING)) { requested = true; + terminator.setProcesses(processes); terminator.start(); } return requested; diff --git a/server/sonar-process-monitor/src/main/java/org/sonar/process/monitor/ProcessRef.java b/server/sonar-process-monitor/src/main/java/org/sonar/process/monitor/ProcessRef.java index f49a75d79a8..ca34de55a5b 100644 --- a/server/sonar-process-monitor/src/main/java/org/sonar/process/monitor/ProcessRef.java +++ b/server/sonar-process-monitor/src/main/java/org/sonar/process/monitor/ProcessRef.java @@ -21,21 +21,21 @@ package org.sonar.process.monitor; import org.slf4j.LoggerFactory; import org.sonar.process.MessageException; +import org.sonar.process.ProcessCommands; import org.sonar.process.ProcessUtils; -import org.sonar.process.SharedStatus; class ProcessRef { private final String key; - private final SharedStatus sharedStatus; + private final ProcessCommands commands; private final Process process; private final StreamGobbler gobbler; private long launchedAt; private volatile boolean stopped = false; - ProcessRef(String key, SharedStatus sharedStatus, Process process, StreamGobbler gobbler) { + ProcessRef(String key, ProcessCommands commands, Process process, StreamGobbler gobbler) { this.key = key; - this.sharedStatus = sharedStatus; + this.commands = commands; this.process = process; this.stopped = !ProcessUtils.isAlive(process); this.gobbler = gobbler; @@ -61,7 +61,7 @@ class ProcessRef { if (isStopped()) { throw new MessageException(String.format("%s failed to start", this)); } - ready = sharedStatus.wasStartedAfter(launchedAt); + ready = commands.wasReadyAfter(launchedAt); try { Thread.sleep(200L); } catch (InterruptedException e) { @@ -75,35 +75,38 @@ class ProcessRef { } /** - * Almost real-time status + * True if process is physically down */ boolean isStopped() { return stopped; } + void askForGracefulAsyncStop() { + commands.askForStop(); + } + /** - * Sends kill signal and awaits termination. + * Sends kill signal and awaits termination. No guarantee that process is gracefully terminated (=shutdown hooks + * executed). It depends on OS. */ - void kill() { + void stop() { if (ProcessUtils.isAlive(process)) { - LoggerFactory.getLogger(getClass()).info(String.format("%s is stopping", this)); - ProcessUtils.sendKillSignal(process); try { - // signal is sent, waiting for shutdown hooks to be executed + ProcessUtils.sendKillSignal(process); + // signal is sent, waiting for shutdown hooks to be executed (or not... it depends on OS) process.waitFor(); - StreamGobbler.waitUntilFinish(gobbler); - ProcessUtils.closeStreams(process); + LoggerFactory.getLogger(getClass()).info(String.format("%s is stopped", this)); + } catch (InterruptedException ignored) { // can't wait for the termination of process. Let's assume it's down. + // TODO log warning } } + ProcessUtils.closeStreams(process); + StreamGobbler.waitUntilFinish(gobbler); stopped = true; } - void setStopped(boolean b) { - this.stopped = b; - } - @Override public String toString() { return String.format("Process[%s]", key); diff --git a/server/sonar-process-monitor/src/main/java/org/sonar/process/monitor/TerminatorThread.java b/server/sonar-process-monitor/src/main/java/org/sonar/process/monitor/TerminatorThread.java index 493be826ae7..b40291f164a 100644 --- a/server/sonar-process-monitor/src/main/java/org/sonar/process/monitor/TerminatorThread.java +++ b/server/sonar-process-monitor/src/main/java/org/sonar/process/monitor/TerminatorThread.java @@ -19,6 +19,9 @@ */ package org.sonar.process.monitor; +import org.slf4j.LoggerFactory; + +import java.util.Collections; import java.util.List; /** @@ -28,19 +31,44 @@ import java.util.List; */ class TerminatorThread extends Thread { - private final List<ProcessRef> processes; + private final Timeouts timeouts; + private List<ProcessRef> processes = Collections.emptyList(); - TerminatorThread(List<ProcessRef> processes) { + TerminatorThread(Timeouts timeouts) { super("Terminator"); - this.processes = processes; + this.timeouts = timeouts; + } + + /** + * To be called before {@link #run()} + */ + void setProcesses(List<ProcessRef> l) { + this.processes = l; } @Override public void run() { // terminate in reverse order of startup (dependency order) for (int index = processes.size() - 1; index >= 0; index--) { - ProcessRef processRef = processes.get(index); - processRef.kill(); + ProcessRef ref = processes.get(index); + if (!ref.isStopped()) { + LoggerFactory.getLogger(getClass()).info(String.format("%s is stopping", ref)); + ref.askForGracefulAsyncStop(); + + long killAt = System.currentTimeMillis() + timeouts.getTerminationTimeout(); + while (!ref.isStopped() && System.currentTimeMillis() < killAt) { + try { + Thread.sleep(100L); + } catch (InterruptedException e) { + // stop asking for graceful stops, Monitor will hardly kill all processes + return; + } + } + if (!ref.isStopped()) { + LoggerFactory.getLogger(getClass()).info(String.format("%s failed to stop in a timely fashion. Killing it.", ref)); + } + ref.stop(); + } } } } diff --git a/server/sonar-process-monitor/src/main/java/org/sonar/process/monitor/Timeouts.java b/server/sonar-process-monitor/src/main/java/org/sonar/process/monitor/Timeouts.java index d9b0b4f6e3e..b89725a9822 100644 --- a/server/sonar-process-monitor/src/main/java/org/sonar/process/monitor/Timeouts.java +++ b/server/sonar-process-monitor/src/main/java/org/sonar/process/monitor/Timeouts.java @@ -24,7 +24,7 @@ package org.sonar.process.monitor; */ class Timeouts { - private long terminationTimeout = 120000L; + private long terminationTimeout = 60000L; /** * [both monitor and monitored process] timeout of graceful termination before hard killing diff --git a/server/sonar-process-monitor/src/main/java/org/sonar/process/monitor/WatcherThread.java b/server/sonar-process-monitor/src/main/java/org/sonar/process/monitor/WatcherThread.java index 4275b6b98a1..d5c9bf6943c 100644 --- a/server/sonar-process-monitor/src/main/java/org/sonar/process/monitor/WatcherThread.java +++ b/server/sonar-process-monitor/src/main/java/org/sonar/process/monitor/WatcherThread.java @@ -19,8 +19,6 @@ */ package org.sonar.process.monitor; -import org.slf4j.LoggerFactory; - /** * This thread blocks as long as the monitored process is physically alive. * It avoids from executing {@link Process#exitValue()} at a fixed rate : @@ -50,12 +48,13 @@ class WatcherThread extends Thread { while (!stopped) { try { processRef.getProcess().waitFor(); - processRef.setStopped(true); - stopped = true; - LoggerFactory.getLogger(getClass()).info(String.format("%s is stopped", processRef)); + + // finalize status of ProcessRef + processRef.stop(); // terminate all other processes, but in another thread monitor.stopAsync(); + stopped = true; } catch (InterruptedException ignored) { // continue to watch process } diff --git a/server/sonar-process-monitor/src/test/java/org/sonar/process/monitor/MonitorTest.java b/server/sonar-process-monitor/src/test/java/org/sonar/process/monitor/MonitorTest.java index b458254d351..5f8f52ceea8 100644 --- a/server/sonar-process-monitor/src/test/java/org/sonar/process/monitor/MonitorTest.java +++ b/server/sonar-process-monitor/src/test/java/org/sonar/process/monitor/MonitorTest.java @@ -232,7 +232,7 @@ public class MonitorTest { private Monitor newDefaultMonitor() { Timeouts timeouts = new Timeouts(); - return new Monitor(new JavaProcessLauncher(timeouts), exit); + return new Monitor(new JavaProcessLauncher(timeouts), exit, new TerminatorThread(timeouts)); } /** |