aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--server/sonar-process-monitor/src/main/java/org/sonar/process/monitor/JavaProcessLauncher.java11
-rw-r--r--server/sonar-process-monitor/src/main/java/org/sonar/process/monitor/Monitor.java6
-rw-r--r--server/sonar-process-monitor/src/main/java/org/sonar/process/monitor/ProcessRef.java7
-rw-r--r--server/sonar-process/src/main/java/org/sonar/process/ProcessCommands.java20
-rw-r--r--server/sonar-process/src/main/java/org/sonar/process/ProcessEntryPoint.java13
-rw-r--r--server/sonar-process/src/main/java/org/sonar/process/StopWatcher.java30
-rw-r--r--server/sonar-process/src/main/java/org/sonar/process/Stoppable.java26
-rw-r--r--server/sonar-process/src/main/java/org/sonar/process/StopperThread.java2
-rw-r--r--server/sonar-process/src/test/java/org/sonar/process/ProcessCommandsTest.java42
-rw-r--r--sonar-application/src/main/java/org/sonar/application/App.java16
10 files changed, 84 insertions, 89 deletions
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 0f2abc34b16..77a4b607d0d 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
@@ -44,23 +44,18 @@ public class JavaProcessLauncher {
ProcessRef launch(JavaCommand command) {
Process process = null;
try {
- // cleanup existing monitor file. Child process creates it when ready.
- // TODO fail if impossible to delete
+ // cleanup existing monitor files
ProcessCommands commands = new ProcessCommands(command.getTempDir(), command.getKey());
- commands.prepareMonitor();
+ commands.prepare();
ProcessBuilder processBuilder = create(command);
LoggerFactory.getLogger(getClass()).info("Launch {}: {}",
command.getKey(), StringUtils.join(processBuilder.command(), " "));
-
- long startedAt = System.currentTimeMillis();
process = processBuilder.start();
StreamGobbler inputGobbler = new StreamGobbler(process.getInputStream(), command.getKey());
inputGobbler.start();
- ProcessRef ref = new ProcessRef(command.getKey(), commands, process, inputGobbler);
- ref.setLaunchedAt(startedAt);
- return ref;
+ return new ProcessRef(command.getKey(), commands, process, inputGobbler);
} catch (Exception e) {
// just in case
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 45141afdc54..72c96d129ba 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
@@ -137,16 +137,12 @@ public class Monitor {
/**
* Asks for processes termination and returns without blocking until termination.
- * @return true if termination was requested, false if it was already being terminated
*/
- boolean stopAsync() {
- boolean requested = false;
+ public void stopAsync() {
if (lifecycle.tryToMoveTo(State.STOPPING)) {
- requested = true;
terminator.setProcesses(processes);
terminator.start();
}
- return requested;
}
public State getState() {
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 ca34de55a5b..672fdf6cb6c 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
@@ -30,7 +30,6 @@ class ProcessRef {
private final ProcessCommands commands;
private final Process process;
private final StreamGobbler gobbler;
- private long launchedAt;
private volatile boolean stopped = false;
ProcessRef(String key, ProcessCommands commands, Process process, StreamGobbler gobbler) {
@@ -61,7 +60,7 @@ class ProcessRef {
if (isStopped()) {
throw new MessageException(String.format("%s failed to start", this));
}
- ready = commands.wasReadyAfter(launchedAt);
+ ready = commands.isReady();
try {
Thread.sleep(200L);
} catch (InterruptedException e) {
@@ -70,10 +69,6 @@ class ProcessRef {
}
}
- void setLaunchedAt(long launchedAt) {
- this.launchedAt = launchedAt;
- }
-
/**
* True if process is physically down
*/
diff --git a/server/sonar-process/src/main/java/org/sonar/process/ProcessCommands.java b/server/sonar-process/src/main/java/org/sonar/process/ProcessCommands.java
index 259af6b1eeb..417d62cb5bf 100644
--- a/server/sonar-process/src/main/java/org/sonar/process/ProcessCommands.java
+++ b/server/sonar-process/src/main/java/org/sonar/process/ProcessCommands.java
@@ -57,22 +57,19 @@ public class ProcessCommands {
this.stopFile = stopFile;
}
- /**
- * Executed by monitor - delete shared files before starting child process
- */
- public void prepareMonitor() {
+ public void prepare() {
deleteFile(readyFile);
deleteFile(stopFile);
}
- public void finalizeProcess() {
+ public void endWatch() {
// do not fail if files can't be deleted
FileUtils.deleteQuietly(readyFile);
FileUtils.deleteQuietly(stopFile);
}
- public boolean wasReadyAfter(long launchedAt) {
- return isCreatedAfter(readyFile, launchedAt);
+ public boolean isReady() {
+ return readyFile.exists();
}
/**
@@ -89,8 +86,8 @@ public class ProcessCommands {
createFile(stopFile);
}
- public boolean askedForStopAfter(long launchedAt) {
- return isCreatedAfter(stopFile, launchedAt);
+ public boolean askedForStop() {
+ return stopFile.exists();
}
File getReadyFile() {
@@ -117,9 +114,4 @@ public class ProcessCommands {
}
}
}
-
- private boolean isCreatedAfter(File file, long launchedAt) {
- // File#lastModified() can have second precision on some OS
- return file.exists() && file.lastModified() / 1000 >= launchedAt / 1000;
- }
}
diff --git a/server/sonar-process/src/main/java/org/sonar/process/ProcessEntryPoint.java b/server/sonar-process/src/main/java/org/sonar/process/ProcessEntryPoint.java
index f4d6e7f90f7..870f1aea067 100644
--- a/server/sonar-process/src/main/java/org/sonar/process/ProcessEntryPoint.java
+++ b/server/sonar-process/src/main/java/org/sonar/process/ProcessEntryPoint.java
@@ -21,7 +21,7 @@ package org.sonar.process;
import org.slf4j.LoggerFactory;
-public class ProcessEntryPoint {
+public class ProcessEntryPoint implements Stoppable {
public static final String PROPERTY_PROCESS_KEY = "process.key";
public static final String PROPERTY_TERMINATION_TIMEOUT = "process.terminationTimeout";
@@ -32,7 +32,6 @@ public class ProcessEntryPoint {
private final ProcessCommands commands;
private final SystemExit exit;
private volatile Monitored monitored;
- private volatile long launchedAt;
private volatile StopperThread stopperThread;
private final StopWatcher stopWatcher;
@@ -49,7 +48,6 @@ public class ProcessEntryPoint {
this.props = props;
this.exit = exit;
this.commands = commands;
- this.launchedAt = System.currentTimeMillis();
this.stopWatcher = new StopWatcher(commands, this);
}
@@ -68,6 +66,7 @@ public class ProcessEntryPoint {
if (!lifecycle.tryToMoveTo(Lifecycle.State.STARTING)) {
throw new IllegalStateException("Already started");
}
+ commands.prepare();
monitored = mp;
try {
@@ -116,10 +115,12 @@ public class ProcessEntryPoint {
exit.exit(0);
}
- void stopAsync() {
+ @Override
+ public void stopAsync() {
if (lifecycle.tryToMoveTo(Lifecycle.State.STOPPING)) {
stopperThread = new StopperThread(monitored, commands, Long.parseLong(props.nonNullValue(PROPERTY_TERMINATION_TIMEOUT)));
stopperThread.start();
+ stopWatcher.stopWatching();
}
}
@@ -131,10 +132,6 @@ public class ProcessEntryPoint {
return shutdownHook;
}
- long getLaunchedAt() {
- return launchedAt;
- }
-
public static ProcessEntryPoint createForArguments(String[] args) {
Props props = ConfigurationUtils.loadPropsFromCommandLineArgs(args);
ProcessCommands commands = new ProcessCommands(
diff --git a/server/sonar-process/src/main/java/org/sonar/process/StopWatcher.java b/server/sonar-process/src/main/java/org/sonar/process/StopWatcher.java
index 090b0052423..b7b4ffa15d8 100644
--- a/server/sonar-process/src/main/java/org/sonar/process/StopWatcher.java
+++ b/server/sonar-process/src/main/java/org/sonar/process/StopWatcher.java
@@ -23,31 +23,35 @@ import org.slf4j.LoggerFactory;
public class StopWatcher extends Thread {
- private final ProcessEntryPoint process;
+ private final Stoppable stoppable;
private final ProcessCommands commands;
private boolean watching = true;
- public StopWatcher(ProcessCommands commands, ProcessEntryPoint process) {
+ public StopWatcher(ProcessCommands commands, Stoppable stoppable) {
super("Stop Watcher");
this.commands = commands;
- this.process = process;
+ this.stoppable = stoppable;
}
@Override
public void run() {
- while (watching) {
- if (commands.askedForStopAfter(process.getLaunchedAt())) {
- LoggerFactory.getLogger(getClass()).info("Stopping process");
- process.stopAsync();
- watching = false;
- } else {
- try {
- Thread.sleep(500L);
- } catch (InterruptedException ignored) {
+ commands.prepare();
+ try {
+ while (watching) {
+ if (commands.askedForStop()) {
+ LoggerFactory.getLogger(getClass()).info("Stopping process");
+ stoppable.stopAsync();
watching = false;
+ } else {
+ try {
+ Thread.sleep(500L);
+ } catch (InterruptedException ignored) {
+ watching = false;
+ }
}
}
-
+ } finally {
+ commands.endWatch();
}
}
diff --git a/server/sonar-process/src/main/java/org/sonar/process/Stoppable.java b/server/sonar-process/src/main/java/org/sonar/process/Stoppable.java
new file mode 100644
index 00000000000..afd464a67a1
--- /dev/null
+++ b/server/sonar-process/src/main/java/org/sonar/process/Stoppable.java
@@ -0,0 +1,26 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * 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.process;
+
+public interface Stoppable {
+
+ void stopAsync();
+
+}
diff --git a/server/sonar-process/src/main/java/org/sonar/process/StopperThread.java b/server/sonar-process/src/main/java/org/sonar/process/StopperThread.java
index 317cd6f62c3..764d551a93c 100644
--- a/server/sonar-process/src/main/java/org/sonar/process/StopperThread.java
+++ b/server/sonar-process/src/main/java/org/sonar/process/StopperThread.java
@@ -57,6 +57,6 @@ class StopperThread extends Thread {
LoggerFactory.getLogger(getClass()).error(String.format("Can not stop in %dms", terminationTimeout), e);
}
executor.shutdownNow();
- commands.finalizeProcess();
+ commands.endWatch();
}
}
diff --git a/server/sonar-process/src/test/java/org/sonar/process/ProcessCommandsTest.java b/server/sonar-process/src/test/java/org/sonar/process/ProcessCommandsTest.java
index 49c8f024c69..e81a537e2ee 100644
--- a/server/sonar-process/src/test/java/org/sonar/process/ProcessCommandsTest.java
+++ b/server/sonar-process/src/test/java/org/sonar/process/ProcessCommandsTest.java
@@ -40,11 +40,11 @@ public class ProcessCommandsTest {
public void delete_files_on_monitor_startup() throws Exception {
File dir = temp.newFolder();
assertThat(dir).exists();
- FileUtils.touch(new File(dir, "WEB.ready"));
- FileUtils.touch(new File(dir, "WEB.stop"));
+ FileUtils.touch(new File(dir, "web.ready"));
+ FileUtils.touch(new File(dir, "web.stop"));
- ProcessCommands commands = new ProcessCommands(dir, "WEB");
- commands.prepareMonitor();
+ ProcessCommands commands = new ProcessCommands(dir, "web");
+ commands.prepare();
assertThat(commands.getReadyFile()).doesNotExist();
assertThat(commands.getStopFile()).doesNotExist();
@@ -58,7 +58,7 @@ public class ProcessCommandsTest {
ProcessCommands commands = new ProcessCommands(readyFile, temp.newFile());
try {
- commands.prepareMonitor();
+ commands.prepare();
fail();
} catch (MessageException e) {
// ok
@@ -70,39 +70,15 @@ public class ProcessCommandsTest {
File readyFile = temp.newFile();
ProcessCommands commands = new ProcessCommands(readyFile, temp.newFile());
- commands.prepareMonitor();
+ commands.prepare();
+ assertThat(commands.isReady()).isFalse();
assertThat(readyFile).doesNotExist();
commands.setReady();
+ assertThat(commands.isReady()).isTrue();
assertThat(readyFile).exists();
- commands.finalizeProcess();
+ commands.endWatch();
assertThat(readyFile).doesNotExist();
}
-
- @Test
- public void was_ready_after_date() throws Exception {
- File readyFile = mock(File.class);
- ProcessCommands commands = new ProcessCommands(readyFile, temp.newFile());
-
- // does not exist
- when(readyFile.exists()).thenReturn(false);
- when(readyFile.lastModified()).thenReturn(123456L);
- assertThat(commands.wasReadyAfter(122000L)).isFalse();
-
- // readyFile created before
- when(readyFile.exists()).thenReturn(true);
- when(readyFile.lastModified()).thenReturn(123456L);
- assertThat(commands.wasReadyAfter(124000L)).isFalse();
-
- // readyFile created after
- when(readyFile.exists()).thenReturn(true);
- when(readyFile.lastModified()).thenReturn(123456L);
- assertThat(commands.wasReadyAfter(123123L)).isTrue();
-
- // readyFile created after, but can be truncated to second on some OS
- when(readyFile.exists()).thenReturn(true);
- when(readyFile.lastModified()).thenReturn(123000L);
- assertThat(commands.wasReadyAfter(123456L)).isTrue();
- }
}
diff --git a/sonar-application/src/main/java/org/sonar/application/App.java b/sonar-application/src/main/java/org/sonar/application/App.java
index db1f9fcb5f6..c051e2f1c8d 100644
--- a/sonar-application/src/main/java/org/sonar/application/App.java
+++ b/sonar-application/src/main/java/org/sonar/application/App.java
@@ -22,8 +22,11 @@ package org.sonar.application;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang.StringUtils;
import org.sonar.process.MinimumViableSystem;
+import org.sonar.process.ProcessCommands;
import org.sonar.process.ProcessLogging;
import org.sonar.process.Props;
+import org.sonar.process.StopWatcher;
+import org.sonar.process.Stoppable;
import org.sonar.process.monitor.JavaCommand;
import org.sonar.process.monitor.Monitor;
@@ -35,7 +38,7 @@ import java.util.Properties;
/**
* Entry-point of process that starts and monitors elasticsearch and web servers
*/
-public class App {
+public class App implements Stoppable {
private final Monitor monitor;
@@ -48,6 +51,12 @@ public class App {
}
public void start(Props props) {
+ if (props.valueAsBoolean("sonar.enableStopCommand", false)) {
+ // stop application when file <temp>/app.stop is created
+ File tempDir = props.nonNullValueAsFile("sonar.path.temp");
+ ProcessCommands commands = new ProcessCommands(tempDir, "app");
+ new StopWatcher(commands, this).start();
+ }
monitor.start(createCommands(props));
monitor.awaitTermination();
}
@@ -103,4 +112,9 @@ public class App {
App app = new App();
app.start(props);
}
+
+ @Override
+ public void stopAsync() {
+ monitor.stopAsync();
+ }
}