From: Stephane Gamard Date: Thu, 10 Jul 2014 13:13:26 +0000 (+0200) Subject: SONAR-5409 - Added monitoring service to sonar-process X-Git-Tag: 4.5-RC1~636 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=2f7578b400c12aaee7c4dadc76183a7406ab3530;p=sonarqube.git SONAR-5409 - Added monitoring service to sonar-process --- diff --git a/server/sonar-process/src/main/java/org/sonar/Application.java b/server/sonar-process/src/main/java/org/sonar/Application.java index 829f264940a..9da457086d1 100644 --- a/server/sonar-process/src/main/java/org/sonar/Application.java +++ b/server/sonar-process/src/main/java/org/sonar/Application.java @@ -21,16 +21,15 @@ package org.sonar; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.sonar.process.Launcher; +import org.sonar.process.MonitorService; +import org.sonar.process.ProcessWrapper; import java.io.IOException; import java.net.DatagramSocket; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; -/** - * @Since 4.5 - */ public class Application { private final static Logger LOGGER = LoggerFactory.getLogger(Application.class); @@ -43,27 +42,39 @@ public class Application { public static void main(String... args) throws InterruptedException, IOException { final ExecutorService executor = Executors.newFixedThreadPool(2); - final Launcher sonarQube = new Launcher("SQ", systemAvailableSocket()); - final Launcher elasticsearch = new Launcher("ES", systemAvailableSocket()); + final MonitorService monitor = new MonitorService(systemAvailableSocket()); + + //Create the processes + //final ProcessWrapper sonarQube = new ProcessWrapper("SQ", monitor); + final ProcessWrapper elasticsearch = null;//new ProcessWrapper("ES", monitor.getMonitoringPort()); + + //Register processes to monitor + monitor.register(elasticsearch); Runtime.getRuntime().addShutdownHook(new Thread() { @Override public void run() { LOGGER.info("Shutting down sonar Node"); - sonarQube.interrupt(); + //sonarQube.shutdown(); elasticsearch.interrupt(); - executor.shutdownNow(); + executor.shutdown(); + try { + executor.awaitTermination(10L, TimeUnit.SECONDS); + } catch (InterruptedException e) { + LOGGER.warn("Executing terminated", e); + } } }); - LOGGER.info("Starting SQ Node..."); - executor.submit(sonarQube); - - LOGGER.info("Starting ES Node..."); + // Start our processes + LOGGER.info("Starting Child processes..."); executor.submit(elasticsearch); + //executor.submit(sonarQube); + + // And monitor the activity + monitor.run(); - while (!executor.isTerminated()) { - Thread.sleep(1000); - } + // If monitor is finished, we're done. Cleanup + executor.shutdown(); } } diff --git a/server/sonar-process/src/main/java/org/sonar/process/Launcher.java b/server/sonar-process/src/main/java/org/sonar/process/Launcher.java deleted file mode 100644 index fd354c48590..00000000000 --- a/server/sonar-process/src/main/java/org/sonar/process/Launcher.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * 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; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.net.DatagramPacket; -import java.net.DatagramSocket; - -/** - * @Since 4.5 - */ -public class Launcher extends Thread { - - private final static Logger LOGGER = LoggerFactory.getLogger(Launcher.class); - - final String name; - final DatagramSocket socket; - java.lang.Process process; - - - public Launcher(String name, DatagramSocket socket) { - LOGGER.info("Creating Launcher for '{}' with base port: {}", name, socket.getLocalPort()); - this.name = name; - this.socket = socket; - } - - private void launch() { -// new Thread(new Runnable() { -// @Override -// public void run() { -// Runner.main(name, socket.getLocalPort() + ""); -// } -// }).start(); - } - - private void shutdown() { - process.destroy(); - } - - private void monitor() { - long ping = Long.MAX_VALUE; - while (true) { - LOGGER.info("My heart is beating"); - DatagramPacket packet = new DatagramPacket(new byte[1024], 1024); - try { - socket.setSoTimeout(3000); - socket.receive(packet); - } catch (Exception e) { - // Do nothing - } - long newPing = System.currentTimeMillis(); - String message = new String(packet.getData(), 0, 0, packet.getLength()); - LOGGER.info("{} last seen since {}ms", message, (newPing - ping)); - if ((newPing - ping) > 3000) { - // close everything here... - } - ping = newPing; - } - } - - @Override - public void run() { - LOGGER.info("launching child VM for " + name); - launch(); - - LOGGER.info("Monitoring VM for " + name); - while (true) { - monitor(); - } - } -} diff --git a/server/sonar-process/src/main/java/org/sonar/process/MonitorService.java b/server/sonar-process/src/main/java/org/sonar/process/MonitorService.java new file mode 100644 index 00000000000..ba4bf7936a5 --- /dev/null +++ b/server/sonar-process/src/main/java/org/sonar/process/MonitorService.java @@ -0,0 +1,81 @@ +package org.sonar.process; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.net.DatagramPacket; +import java.net.DatagramSocket; +import java.util.HashMap; +import java.util.Map; + +public class MonitorService extends Thread { + + private final static Logger LOGGER = LoggerFactory.getLogger(ProcessWrapper.class); + + final DatagramSocket socket; + final Map processes; + final Map processesPing; + + public MonitorService(DatagramSocket socket) { + this.socket = socket; + processes = new HashMap(); + processesPing = new HashMap(); + } + + public void register(ProcessWrapper process) { + this.processes.put(process.getName(), process); + this.processesPing.put(process.getName(), System.currentTimeMillis()); + } + + @Override + public void run() { + LOGGER.info("Launching Monitoring Thread"); + long time = System.currentTimeMillis(); + while (!currentThread().isInterrupted()) { + DatagramPacket packet = new DatagramPacket(new byte[1024], 1024); + try { + socket.setSoTimeout(200); + socket.receive(packet); + time = System.currentTimeMillis(); + String message = new String(packet.getData()); + long lastTime = processesPing.get(message); + processesPing.put(message, time); + LOGGER.info("{} last seen since {}ms", message, (time - lastTime)); + } catch (Exception e) { + // Do nothing + } + if (!checkAllProcessPing(time)) { + break; + } + } + LOGGER.info("Some app has not been pinging"); + for (Thread process : processes.values()) { + if (!process.isInterrupted()) { + process.interrupt(); + } + } + } + + + private boolean checkAllProcessPing(long now) { + + //check that all thread wrapper are running + for (Thread thread : processes.values()) { + if (thread.isInterrupted() || !thread.isAlive()) { + return false; + } + } + + //check that all heartbeats are OK + for (Long ping : processesPing.values()) { + if ((now - ping) > 3000) { + return false; + } + } + return true; + } + + public Integer getMonitoringPort() { + return socket.getPort(); + } +} diff --git a/server/sonar-process/src/main/java/org/sonar/process/Process.java b/server/sonar-process/src/main/java/org/sonar/process/Process.java index b0adaf64431..f170eb393c3 100644 --- a/server/sonar-process/src/main/java/org/sonar/process/Process.java +++ b/server/sonar-process/src/main/java/org/sonar/process/Process.java @@ -28,9 +28,6 @@ import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; -/** - * @Since 4.5 - */ public abstract class Process implements Runnable { public static final String NAME_PROPERTY = "pName"; diff --git a/server/sonar-process/src/main/java/org/sonar/process/ProcessWrapper.java b/server/sonar-process/src/main/java/org/sonar/process/ProcessWrapper.java new file mode 100644 index 00000000000..03190f0b440 --- /dev/null +++ b/server/sonar-process/src/main/java/org/sonar/process/ProcessWrapper.java @@ -0,0 +1,46 @@ +/* + * 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; + +import com.google.common.annotations.VisibleForTesting; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class ProcessWrapper extends Thread { + + private final static Logger LOGGER = LoggerFactory.getLogger(ProcessWrapper.class); + + final String name; + + @VisibleForTesting + ProcessWrapper(String name, Integer port) { + LOGGER.info("Creating Launcher for '{}' with base port: {}", name, port); + this.name = name; + } + + public ProcessWrapper(String className, String[] classPath, String name, Integer port) { + LOGGER.info("Creating Launcher for '{}' with base port: {}", name, port); + this.name = name; + } + + public void run() { + + } +} diff --git a/server/sonar-process/src/test/java/org/sonar/process/LauncherTest.java b/server/sonar-process/src/test/java/org/sonar/process/LauncherTest.java deleted file mode 100644 index 22bdd9683a6..00000000000 --- a/server/sonar-process/src/test/java/org/sonar/process/LauncherTest.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * 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 class LauncherTest { - -} \ No newline at end of file diff --git a/server/sonar-process/src/test/java/org/sonar/process/MonitorServiceTest.java b/server/sonar-process/src/test/java/org/sonar/process/MonitorServiceTest.java new file mode 100644 index 00000000000..4723c22a8e1 --- /dev/null +++ b/server/sonar-process/src/test/java/org/sonar/process/MonitorServiceTest.java @@ -0,0 +1,46 @@ +package org.sonar.process; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import java.net.DatagramSocket; + +public class MonitorServiceTest { + + + private DatagramSocket socket; + + @Before + public void setUp() throws Exception { + socket = new DatagramSocket(0); + } + + @After + public void tearDown() throws Exception { + if (socket != null && !socket.isClosed()) { + socket.close(); + } + } + + @Test + public void should_build() { + MonitorService monitor = new MonitorService(socket); + } + + class LongProcessWrapper extends ProcessWrapper { + + LongProcessWrapper(String name, Integer port) { + super(name, port); + } + + @Override + public void run() { + try { + Thread.sleep(10000L); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } +} \ No newline at end of file