]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-4898 simplify MonitoredProcess implementations
authorSimon Brandhof <simon.brandhof@sonarsource.com>
Fri, 12 Sep 2014 13:29:57 +0000 (15:29 +0200)
committerSimon Brandhof <simon.brandhof@sonarsource.com>
Fri, 12 Sep 2014 13:29:57 +0000 (15:29 +0200)
server/sonar-process-monitor/src/main/java/org/sonar/process/monitor/RmiJmxConnector.java
server/sonar-process-monitor/src/main/java/org/sonar/process/monitor/TerminatorThread.java
server/sonar-process/src/main/java/org/sonar/process/MonitoredProcess.java
server/sonar-process/src/main/java/org/sonar/process/ProcessEntryPoint.java
server/sonar-process/src/test/java/org/sonar/process/ProcessEntryPointTest.java
server/sonar-process/src/test/java/org/sonar/process/test/HttpProcess.java
server/sonar-process/src/test/java/org/sonar/process/test/StandardProcess.java
server/sonar-search/src/main/java/org/sonar/search/SearchServer.java
server/sonar-server/src/main/java/org/sonar/server/app/EmbeddedTomcat.java
server/sonar-server/src/main/java/org/sonar/server/app/WebServer.java

index ec8dba2902a2c255882dbd5afbb19b17cd30068c..876ccc2b22f6fc108cb33f1eb9f522a20c26b042 100644 (file)
@@ -19,6 +19,7 @@
  */
 package org.sonar.process.monitor;
 
+import org.slf4j.LoggerFactory;
 import org.sonar.process.JmxUtils;
 import org.sonar.process.LoopbackAddress;
 import org.sonar.process.ProcessMXBean;
@@ -92,6 +93,7 @@ class RmiJmxConnector implements JmxConnector {
     execute(new Callable() {
       @Override
       public Void call() throws Exception {
+        LoggerFactory.getLogger(getClass()).info("Request termination of " + processRef);
         mbeans.get(processRef).terminate();
         return null;
       }
index f0943086877f1f62c03b8ed6b95d40b242fe7c53..f5b11b3148f59fdd29beb58f3bd1ce488b694a16 100644 (file)
@@ -48,7 +48,6 @@ class TerminatorThread extends Thread {
       final ProcessRef processRef = processes.get(index);
       if (!processRef.isTerminated()) {
         processRef.setPingEnabled(false);
-
         try {
           jmxConnector.terminate(processRef, timeouts.getTerminationTimeout());
         } catch (Exception ignored) {
index 6ee84d00744b7688b6761663bac6f2890b553af6..11ddf54beec4ed8492aca86526210a7aa03a4921 100644 (file)
@@ -22,10 +22,20 @@ package org.sonar.process;
 public interface MonitoredProcess extends Terminable {
 
   /**
-   * Starts and blocks until ready
+   * Starts process. No need to block until fully started and operational.
    */
   void start();
 
+  /**
+   * True if the process is started and operational (-> can accept requests), false if
+   * it's still starting. An exception is thrown is process failed to start (not starting
+   * nor started).
+   */
+  boolean isReady();
+
+  /**
+   * Blocks until the process is terminated
+   */
   void awaitTermination();
 
 }
index 6990545a5710df51536e2adb1d58e9ffbead8e9a..7137a41fa123b623d1a06adeaf7777806fadf2a2 100644 (file)
@@ -75,10 +75,17 @@ public class ProcessEntryPoint implements ProcessMXBean {
 
     try {
       monitoredProcess.start();
+      boolean ready = false;
+      while (!ready) {
+        ready = monitoredProcess.isReady();
+        Thread.sleep(200L);
+      }
       if (lifecycle.tryToMoveTo(State.STARTED)) {
         monitoredProcess.awaitTermination();
       }
-    } catch (Exception ignored) {
+    } catch (Exception e) {
+      LoggerFactory.getLogger(getClass()).warn("Fail to start", e);
+
     } finally {
       terminate();
     }
@@ -86,7 +93,6 @@ public class ProcessEntryPoint implements ProcessMXBean {
 
   @Override
   public boolean isReady() {
-    LoggerFactory.getLogger(getClass()).warn("Received JMX request isReady: " + (lifecycle.getState() == State.STARTED));
     return lifecycle.getState() == State.STARTED;
   }
 
index 55bf8d679d16322cc195b66d5c86feca44272332..03cd7409a49885e6d4d403360c2eba2557de71fd 100644 (file)
@@ -193,6 +193,11 @@ public class ProcessEntryPointTest {
 
     }
 
+    @Override
+    public boolean isReady() {
+      return true;
+    }
+
     @Override
     public void awaitTermination() {
 
@@ -211,6 +216,11 @@ public class ProcessEntryPointTest {
       throw new IllegalStateException("ERROR");
     }
 
+    @Override
+    public boolean isReady() {
+      return false;
+    }
+
     @Override
     public void awaitTermination() {
 
index 307abed6d0b80dda7e4915abbd588e917cc62426..f6ca587a58805a62e1ba53d99447582efbfb0828 100644 (file)
@@ -42,6 +42,7 @@ import java.io.IOException;
 public class HttpProcess implements MonitoredProcess {
 
   private final Server server;
+  private boolean ready = false;
   // temp dir is specific to this process
   private final File tempDir = new File(System.getProperty("java.io.tmpdir"));
 
@@ -70,16 +71,23 @@ public class HttpProcess implements MonitoredProcess {
     });
     try {
       server.start();
-      while (!server.isStarted()) {
-        Thread.sleep(100L);
-      }
-      writeTimeToFile("readyAt");
-
     } catch (Exception e) {
       throw new IllegalStateException("Fail to start Jetty", e);
     }
   }
 
+  @Override
+  public boolean isReady() {
+    if (ready) {
+      return true;
+    }
+    if (server.isStarted()) {
+      ready = true;
+      writeTimeToFile("readyAt");
+    }
+    return false;
+  }
+
   @Override
   public void awaitTermination() {
     try {
index 121784f633b8a00d6e616809ae89846d0bf2280d..4c1a33221c62c54f90e61925d92f435d74d84a5f 100644 (file)
@@ -50,6 +50,11 @@ public class StandardProcess implements MonitoredProcess {
     state = State.STARTED;
   }
 
+  @Override
+  public boolean isReady() {
+    return state == State.STARTED;
+  }
+
   @Override
   public void awaitTermination() {
     try {
index cf7eb1682df8c1bd66646f9d9365fe3528d963e8..d2aa111e7e50b3b0f266f5c22c937aa5a63a303d 100644 (file)
@@ -143,20 +143,11 @@ public class SearchServer implements MonitoredProcess {
         .setTemplate("*")
         .addMapping("_default_", "{\"dynamic\": \"strict\"}")
         .get();
-
-      boolean ready = false;
-      while (!ready) {
-        ready = isReady();
-        try {
-          Thread.sleep(300L);
-        } catch (InterruptedException e) {
-          e.printStackTrace();
-        }
-      }
     }
   }
 
-  boolean isReady() {
+  @Override
+  public boolean isReady() {
     return node.client().admin().cluster().prepareHealth()
       .setWaitForYellowStatus()
       .setTimeout(TimeValue.timeValueSeconds(3L))
index a7146eda913689275445a4f623c9aa0d182c12a7..01a5305c53dd46d2fd96912047e768de8af64ea0 100644 (file)
 package org.sonar.server.app;
 
 import com.google.common.base.Throwables;
-import com.google.common.util.concurrent.Uninterruptibles;
-import org.apache.catalina.Container;
-import org.apache.catalina.Executor;
-import org.apache.catalina.Lifecycle;
-import org.apache.catalina.LifecycleEvent;
-import org.apache.catalina.LifecycleListener;
-import org.apache.catalina.LifecycleState;
-import org.apache.catalina.Server;
-import org.apache.catalina.Service;
-import org.apache.catalina.connector.Connector;
+import org.apache.catalina.LifecycleException;
 import org.apache.catalina.core.StandardContext;
 import org.apache.catalina.startup.Tomcat;
 import org.apache.commons.io.FileUtils;
@@ -37,13 +28,11 @@ import org.slf4j.LoggerFactory;
 import org.sonar.process.Props;
 
 import java.io.File;
-import java.util.concurrent.TimeUnit;
 
 class EmbeddedTomcat {
 
   private final Props props;
   private Tomcat tomcat = null;
-  private Thread hook = null;
   private volatile StandardContext webappContext;
 
   EmbeddedTomcat(Props props) {
@@ -51,53 +40,43 @@ class EmbeddedTomcat {
   }
 
   void start() {
-    if (tomcat != null || hook != null) {
-      throw new IllegalStateException("Server is already started");
-    }
-
-    try {
-      // '%2F' (slash /) and '%5C' (backslash \) are permitted as path delimiters in URLs
-      // See Ruby on Rails url_for
-      System.setProperty("org.apache.tomcat.util.buf.UDecoder.ALLOW_ENCODED_SLASH", "true");
+    // '%2F' (slash /) and '%5C' (backslash \) are permitted as path delimiters in URLs
+    // See Ruby on Rails url_for
+    System.setProperty("org.apache.tomcat.util.buf.UDecoder.ALLOW_ENCODED_SLASH", "true");
 
-      System.setProperty("org.apache.catalina.startup.EXIT_ON_INIT_FAILURE", "true");
+    System.setProperty("org.apache.catalina.startup.EXIT_ON_INIT_FAILURE", "true");
 
-      tomcat = new Tomcat();
-      // Initialize directories
-      String basedir = tomcatBasedir().getAbsolutePath();
-      tomcat.setBaseDir(basedir);
-      tomcat.getHost().setAppBase(basedir);
-      tomcat.getHost().setAutoDeploy(false);
-      tomcat.getHost().setCreateDirs(false);
-      tomcat.getHost().setDeployOnStartup(true);
-      Logging.configure(tomcat, props);
-      Connectors.configure(tomcat, props);
-      webappContext = Webapp.configure(tomcat, props);
+    tomcat = new Tomcat();
+    // Initialize directories
+    String basedir = tomcatBasedir().getAbsolutePath();
+    tomcat.setBaseDir(basedir);
+    tomcat.getHost().setAppBase(basedir);
+    tomcat.getHost().setAutoDeploy(false);
+    tomcat.getHost().setCreateDirs(false);
+    tomcat.getHost().setDeployOnStartup(true);
+    Logging.configure(tomcat, props);
+    Connectors.configure(tomcat, props);
+    webappContext = Webapp.configure(tomcat, props);
+    try {
       tomcat.start();
-      waitForWebappReady();
-
-    } catch (Exception e) {
+    } catch (LifecycleException e) {
       Throwables.propagate(e);
     }
   }
 
-  private void waitForWebappReady() {
-    while (true) {
-      switch (webappContext.getState()) {
-        case NEW:
-        case INITIALIZING:
-        case INITIALIZED:
-        case STARTING_PREP:
-        case STARTING:
-          Uninterruptibles.sleepUninterruptibly(300L, TimeUnit.MILLISECONDS);
-          break;
-        case STARTED:
-          // ok
-          return;
-        default:
-          // problem, stopped or failed
-          throw new IllegalStateException("YYY Webapp did not start");
-      }
+  boolean isReady() {
+    switch (webappContext.getState()) {
+      case NEW:
+      case INITIALIZING:
+      case INITIALIZED:
+      case STARTING_PREP:
+      case STARTING:
+        return false;
+      case STARTED:
+        return true;
+      default:
+        // problem, stopped or failed
+        throw new IllegalStateException("Webapp did not start");
     }
   }
 
index 94bc1214f0f48fcc0aa0104fa335fe742ef63079..87ffa5c5beefbc31267ac1b583713163797253e3 100644 (file)
@@ -40,6 +40,11 @@ public class WebServer implements MonitoredProcess {
     tomcat.start();
   }
 
+  @Override
+  public boolean isReady() {
+    return tomcat.isReady();
+  }
+
   @Override
   public void terminate() {
     tomcat.terminate();