]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-8435 add abort exit points to AutoStarter when shutdown while running
authorSébastien Lesaint <sebastien.lesaint@sonarsource.com>
Tue, 21 Feb 2017 11:24:07 +0000 (12:24 +0100)
committerSébastien Lesaint <sebastien.lesaint@sonarsource.com>
Fri, 24 Feb 2017 19:27:07 +0000 (20:27 +0100)
server/sonar-server/src/main/java/org/sonar/server/platform/Platform.java
server/sonar-server/src/test/java/org/sonar/server/platform/ServerTesterPlatform.java
server/sonar-server/src/test/java/org/sonar/server/tester/ServerTester.java

index d74834f8deacaccc5dc17dbcb99657ca7702f048..2622ab4d28a8ac08d526796e35cfdec5e68036c2 100644 (file)
@@ -49,8 +49,8 @@ public class Platform {
 
   private static final Platform INSTANCE = new Platform();
 
-  private final Supplier<PlatformAutoStarter> autoStarterSupplier;
-  private PlatformAutoStarter autoStarter = null;
+  private final Supplier<AutoStarter> autoStarterSupplier;
+  private AutoStarter autoStarter = null;
   private Properties properties;
   private ServletContext servletContext;
   private PlatformLevel level1;
@@ -71,7 +71,7 @@ public class Platform {
     };
   }
 
-  protected Platform(Supplier<PlatformAutoStarter> autoStarterSupplier) {
+  protected Platform(Supplier<AutoStarter> autoStarterSupplier) {
     this.autoStarterSupplier = autoStarterSupplier;
   }
 
@@ -110,23 +110,20 @@ public class Platform {
       LOGGER.info("Database needs migration");
     } else {
       this.autoStarter = autoStarterSupplier.get();
-      this.autoStarter.execute(() ->  {
-        try {
+      this.autoStarter.execute(new AutoStarterRunnable(autoStarter) {
+        @Override
+        public void doRun() {
           if (dbRequiredMigration) {
             LOGGER.info("Database has been automatically updated");
           }
-          startLevel34Containers();
+          runIfNotAborted(Platform.this::startLevel34Containers);
 
-          executeStartupTasks(startup);
+          runIfNotAborted(() -> executeStartupTasks(startup));
           // switch current container last to avoid giving access to a partially initialized container
-          currentLevel = level4;
+          runIfNotAborted(() -> currentLevel = level4);
 
           // stop safemode container if it existed
-          stopSafeModeContainer();
-        } catch (Throwable t) {
-          autoStarter.failure(t);
-        } finally {
-          autoStarter.success();
+          runIfNotAborted(Platform.this::stopSafeModeContainer);
         }
       });
     }
@@ -179,7 +176,7 @@ public class Platform {
     return Status.BOOTING;
   }
 
-  private static boolean isRunning(@Nullable PlatformAutoStarter autoStarter) {
+  private static boolean isRunning(@Nullable AutoStarter autoStarter) {
     return autoStarter != null && autoStarter.isRunning();
   }
 
@@ -280,10 +277,10 @@ public class Platform {
   // Do not rename "stop"
   public void doStop() {
     try {
+      stopAutoStarter();
       stopSafeModeContainer();
       stopLevel234Containers();
       stopLevel1Container();
-      autoStarter = null;
       currentLevel = null;
       dbConnected = false;
       started = false;
@@ -292,6 +289,13 @@ public class Platform {
     }
   }
 
+  private void stopAutoStarter() {
+    if (autoStarter != null) {
+      autoStarter.abort();
+      autoStarter = null;
+    }
+  }
+
   public void addComponents(Collection<?> components) {
     level4AddedComponents.addAll(components);
   }
@@ -312,7 +316,7 @@ public class Platform {
     NO_STARTUP_TASKS, ALL
   }
 
-  public interface PlatformAutoStarter {
+  public interface AutoStarter {
     /**
      * Let the autostarted execute the provided code.
      */
@@ -332,11 +336,64 @@ public class Platform {
      * Indicates whether the AutoStarter is running.
      */
     boolean isRunning();
+
+    /**
+     * Requests the startcode (ie. the argument of {@link #execute(Runnable)}) aborts its processing (if it supports it).
+     */
+    void abort();
+
+    /**
+     * Indicates whether {@link #abort()} was invoked.
+     * <p>
+     * This method can be used by the start code to check whether it should proceed running or stop.
+     * </p>
+     */
+    boolean isAborting();
+
+    /**
+     * Called when abortion is complete.
+     * <p>
+     * Start code support abortion should call this method once is done processing and if it stopped on abortion.
+     * </p>
+     */
+    void aborted();
   }
 
-  private static final class AsynchronousAutoStarter implements PlatformAutoStarter {
+  private abstract static class AutoStarterRunnable implements Runnable {
+    private final AutoStarter autoStarter;
+
+    AutoStarterRunnable(AutoStarter autoStarter) {
+      this.autoStarter = autoStarter;
+    }
+
+    @Override
+    public void run() {
+      try {
+        doRun();
+      } catch (Throwable t) {
+        autoStarter.failure(t);
+      } finally {
+        if (autoStarter.isAborting()) {
+          autoStarter.aborted();
+        } else {
+          autoStarter.success();
+        }
+      }
+    }
+
+    abstract void doRun();
+
+    void runIfNotAborted(Runnable r) {
+      if (!autoStarter.isAborting()) {
+        r.run();
+      }
+    }
+  }
+
+  private static final class AsynchronousAutoStarter implements AutoStarter {
     private final ProcessCommandWrapper processCommandWrapper;
     private boolean running = true;
+    private boolean abort = false;
 
     private AsynchronousAutoStarter(ProcessCommandWrapper processCommandWrapper) {
       this.processCommandWrapper = processCommandWrapper;
@@ -356,6 +413,13 @@ public class Platform {
 
     @Override
     public void success() {
+      LOGGER.debug("Background initialization of SonarQube done");
+      this.running = false;
+    }
+
+    @Override
+    public void aborted() {
+      LOGGER.debug("Background initialization of SonarQube aborted");
       this.running = false;
     }
 
@@ -363,5 +427,15 @@ public class Platform {
     public boolean isRunning() {
       return running;
     }
+
+    @Override
+    public void abort() {
+      this.abort = true;
+    }
+
+    @Override
+    public boolean isAborting() {
+      return this.abort;
+    }
   }
 }
index a1fd38d25dff106c9e94437c5bf90e2f04c0abc7..ca2a3f4324ed106471add416329f075ce02857e1 100644 (file)
@@ -22,7 +22,7 @@ package org.sonar.server.platform;
 import java.util.function.Supplier;
 
 public class ServerTesterPlatform extends Platform {
-  public ServerTesterPlatform(Supplier<PlatformAutoStarter> autoStarterFactory) {
+  public ServerTesterPlatform(Supplier<AutoStarter> autoStarterFactory) {
     super(autoStarterFactory);
   }
 
index 897c601a74abbd3ebdd905b8c1746c00b2267e05..d7862d6ce0dea6e92118351e8af5f51a38c25a45 100644 (file)
@@ -125,7 +125,7 @@ public class ServerTester extends ExternalResource {
       if (!esIndexes) {
         properties.put("sonar.internal.es.disableIndexes", true);
       }
-      platform = new ServerTesterPlatform(() -> new Platform.PlatformAutoStarter() {
+      platform = new ServerTesterPlatform(() -> new Platform.AutoStarter() {
         private boolean running = false;
 
         @Override
@@ -150,6 +150,21 @@ public class ServerTester extends ExternalResource {
         public boolean isRunning() {
           return this.running;
         }
+
+        @Override
+        public void abort() {
+          // do nothing specific
+        }
+
+        @Override
+        public boolean isAborting() {
+          return false;
+        }
+
+        @Override
+        public void aborted() {
+          // do nothing specific
+        }
       });
       platform.init(properties, servletContext);
       platform.addComponents(components);