aboutsummaryrefslogtreecommitdiffstats
path: root/server/sonar-process-monitor
diff options
context:
space:
mode:
authorJenkins CI <ci@sonarsource.com>2014-09-22 17:59:10 +0200
committerJenkins CI <ci@sonarsource.com>2014-09-22 17:59:10 +0200
commit5506038e6bebe3c0be5d7d3c099c4e6f73e315be (patch)
tree5e554ea1f9467b8060cbe075ce61d1ae3b97b501 /server/sonar-process-monitor
parent8a7965dfbc7c967e199d5cf4f4c83ff8dd81a6c3 (diff)
parent92c30ccd4cd311dc602c0e1a08fc97c09970a4f6 (diff)
downloadsonarqube-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')
-rw-r--r--server/sonar-process-monitor/src/main/java/org/sonar/process/monitor/JavaCommand.java7
-rw-r--r--server/sonar-process-monitor/src/main/java/org/sonar/process/monitor/JavaProcessLauncher.java10
-rw-r--r--server/sonar-process-monitor/src/main/java/org/sonar/process/monitor/Monitor.java7
-rw-r--r--server/sonar-process-monitor/src/main/java/org/sonar/process/monitor/ProcessRef.java37
-rw-r--r--server/sonar-process-monitor/src/main/java/org/sonar/process/monitor/TerminatorThread.java38
-rw-r--r--server/sonar-process-monitor/src/main/java/org/sonar/process/monitor/Timeouts.java2
-rw-r--r--server/sonar-process-monitor/src/main/java/org/sonar/process/monitor/WatcherThread.java9
-rw-r--r--server/sonar-process-monitor/src/test/java/org/sonar/process/monitor/MonitorTest.java2
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));
}
/**