From e09aed353ec5539a1e326e3f8c6bcf6be3dca727 Mon Sep 17 00:00:00 2001 From: =?utf8?q?S=C3=A9bastien=20Lesaint?= Date: Wed, 22 Nov 2017 16:34:08 +0100 Subject: [PATCH] SONAR-10112 add MBean to monitor queue and workers of AsyncExecution --- .../async/SynchronousAsyncExecutionTest.java | 19 ++++ .../ce/monitoring/CeTasksMBeanImplTest.java | 32 +++---- .../AsyncExecutionExecutorServiceImpl.java | 20 ++++- .../server/async/AsyncExecutionMBean.java | 31 +++++++ .../server/async/AsyncExecutionMBeanImpl.java | 57 ++++++++++++ .../server/async/AsyncExecutionModule.java | 1 + .../async/AsyncExecutionMonitoring.java | 28 ++++++ .../async/AsyncExecutionMBeanImplTest.java | 87 +++++++++++++++++++ 8 files changed, 256 insertions(+), 19 deletions(-) create mode 100644 server/sonar-server/src/main/java/org/sonar/server/async/AsyncExecutionMBean.java create mode 100644 server/sonar-server/src/main/java/org/sonar/server/async/AsyncExecutionMBeanImpl.java create mode 100644 server/sonar-server/src/main/java/org/sonar/server/async/AsyncExecutionMonitoring.java create mode 100644 server/sonar-server/src/test/java/org/sonar/server/async/AsyncExecutionMBeanImplTest.java diff --git a/server/sonar-ce/src/test/java/org/sonar/ce/async/SynchronousAsyncExecutionTest.java b/server/sonar-ce/src/test/java/org/sonar/ce/async/SynchronousAsyncExecutionTest.java index 57f0a7163df..a8c6c4ee972 100644 --- a/server/sonar-ce/src/test/java/org/sonar/ce/async/SynchronousAsyncExecutionTest.java +++ b/server/sonar-ce/src/test/java/org/sonar/ce/async/SynchronousAsyncExecutionTest.java @@ -1,3 +1,22 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program 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. + * + * This program 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.ce.async; import java.util.HashSet; diff --git a/server/sonar-ce/src/test/java/org/sonar/ce/monitoring/CeTasksMBeanImplTest.java b/server/sonar-ce/src/test/java/org/sonar/ce/monitoring/CeTasksMBeanImplTest.java index c161c86d5a8..da5997c3f00 100644 --- a/server/sonar-ce/src/test/java/org/sonar/ce/monitoring/CeTasksMBeanImplTest.java +++ b/server/sonar-ce/src/test/java/org/sonar/ce/monitoring/CeTasksMBeanImplTest.java @@ -52,6 +52,19 @@ public class CeTasksMBeanImplTest { assertThat(getMBean()).isNull(); } + /** + * Dumb implementation of CEQueueStatus which returns constant values for get methods and throws UnsupportedOperationException + * for other methods. + */ + @CheckForNull + private ObjectInstance getMBean() throws Exception { + try { + return ManagementFactory.getPlatformMBeanServer().getObjectInstance(new ObjectName(CeTasksMBean.OBJECT_NAME)); + } catch (InstanceNotFoundException e) { + return null; + } + } + @Test public void get_methods_delegate_to_the_CEQueueStatus_instance() { assertThat(underTest.getPendingCount()).isEqualTo(PENDING_COUNT); @@ -77,13 +90,9 @@ public class CeTasksMBeanImplTest { assertThat(section.getName()).isEqualTo("Compute Engine Tasks"); assertThat(section.getAttributesCount()).isEqualTo(7); } - - /** - * Dumb implementation of CEQueueStatus which returns constant values for get methods and throws UnsupportedOperationException - * for other methods. - */ private static class DumbCEQueueStatus implements CEQueueStatus { + @Override public long getPendingCount() { return PENDING_COUNT; @@ -123,13 +132,13 @@ public class CeTasksMBeanImplTest { public long getProcessingTime() { return PROCESSING_TIME; } - private long methodNotImplemented() { throw new UnsupportedOperationException("Not Implemented"); } - } + } private static class DumbCeConfiguration implements CeConfiguration { + @Override public void refresh() { throw new UnsupportedOperationException("Refresh is not implemented"); @@ -166,13 +175,4 @@ public class CeTasksMBeanImplTest { } } - - @CheckForNull - private ObjectInstance getMBean() throws Exception { - try { - return ManagementFactory.getPlatformMBeanServer().getObjectInstance(new ObjectName(CeTasksMBean.OBJECT_NAME)); - } catch (InstanceNotFoundException e) { - return null; - } - } } diff --git a/server/sonar-server/src/main/java/org/sonar/server/async/AsyncExecutionExecutorServiceImpl.java b/server/sonar-server/src/main/java/org/sonar/server/async/AsyncExecutionExecutorServiceImpl.java index 60c87fc9fa6..f329d52ec40 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/async/AsyncExecutionExecutorServiceImpl.java +++ b/server/sonar-server/src/main/java/org/sonar/server/async/AsyncExecutionExecutorServiceImpl.java @@ -20,7 +20,6 @@ package org.sonar.server.async; import com.google.common.util.concurrent.ThreadFactoryBuilder; -import java.util.concurrent.ExecutorService; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; import org.sonar.api.utils.log.Logger; @@ -30,8 +29,8 @@ import org.sonar.server.util.AbstractStoppableExecutorService; import static java.util.concurrent.TimeUnit.MILLISECONDS; public class AsyncExecutionExecutorServiceImpl - extends AbstractStoppableExecutorService - implements AsyncExecutionExecutorService { + extends AbstractStoppableExecutorService + implements AsyncExecutionExecutorService, AsyncExecutionMonitoring { private static final Logger LOG = Loggers.get(AsyncExecutionExecutorServiceImpl.class); private static final int MIN_THREAD_COUNT = 1; @@ -56,4 +55,19 @@ public class AsyncExecutionExecutorServiceImpl public void addToQueue(Runnable r) { this.submit(r); } + + @Override + public int getQueueSize() { + return delegate.getQueue().size(); + } + + @Override + public int getWorkerCount() { + return delegate.getPoolSize(); + } + + @Override + public int getLargestWorkerCount() { + return delegate.getLargestPoolSize(); + } } diff --git a/server/sonar-server/src/main/java/org/sonar/server/async/AsyncExecutionMBean.java b/server/sonar-server/src/main/java/org/sonar/server/async/AsyncExecutionMBean.java new file mode 100644 index 00000000000..08de7ef7a93 --- /dev/null +++ b/server/sonar-server/src/main/java/org/sonar/server/async/AsyncExecutionMBean.java @@ -0,0 +1,31 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program 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. + * + * This program 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.server.async; + +public interface AsyncExecutionMBean { + + String OBJECT_NAME = "SonarQube:name=AsyncExecution"; + + long getQueueSize(); + + long getWorkerCount(); + + long getLargestWorkerCount(); +} diff --git a/server/sonar-server/src/main/java/org/sonar/server/async/AsyncExecutionMBeanImpl.java b/server/sonar-server/src/main/java/org/sonar/server/async/AsyncExecutionMBeanImpl.java new file mode 100644 index 00000000000..b562fa80f0b --- /dev/null +++ b/server/sonar-server/src/main/java/org/sonar/server/async/AsyncExecutionMBeanImpl.java @@ -0,0 +1,57 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program 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. + * + * This program 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.server.async; + +import org.picocontainer.Startable; +import org.sonar.process.Jmx; + +public class AsyncExecutionMBeanImpl implements AsyncExecutionMBean, Startable { + + private final AsyncExecutionMonitoring asyncExecutionMonitoring; + + public AsyncExecutionMBeanImpl(AsyncExecutionMonitoring asyncExecutionMonitoring) { + this.asyncExecutionMonitoring = asyncExecutionMonitoring; + } + + @Override + public void start() { + Jmx.register(OBJECT_NAME, this); + } + + @Override + public void stop() { + Jmx.unregister(OBJECT_NAME); + } + + @Override + public long getQueueSize() { + return asyncExecutionMonitoring.getQueueSize(); + } + + @Override + public long getWorkerCount() { + return asyncExecutionMonitoring.getWorkerCount(); + } + + @Override + public long getLargestWorkerCount() { + return asyncExecutionMonitoring.getLargestWorkerCount(); + } +} diff --git a/server/sonar-server/src/main/java/org/sonar/server/async/AsyncExecutionModule.java b/server/sonar-server/src/main/java/org/sonar/server/async/AsyncExecutionModule.java index 1e5673c45ee..2d16d0bac76 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/async/AsyncExecutionModule.java +++ b/server/sonar-server/src/main/java/org/sonar/server/async/AsyncExecutionModule.java @@ -25,6 +25,7 @@ public class AsyncExecutionModule extends Module { @Override protected void configureModule() { add( + AsyncExecutionMBeanImpl.class, AsyncExecutionExecutorServiceImpl.class, AsyncExecutionImpl.class); } diff --git a/server/sonar-server/src/main/java/org/sonar/server/async/AsyncExecutionMonitoring.java b/server/sonar-server/src/main/java/org/sonar/server/async/AsyncExecutionMonitoring.java new file mode 100644 index 00000000000..f65a5096f11 --- /dev/null +++ b/server/sonar-server/src/main/java/org/sonar/server/async/AsyncExecutionMonitoring.java @@ -0,0 +1,28 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program 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. + * + * This program 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.server.async; + +public interface AsyncExecutionMonitoring { + int getQueueSize(); + + int getWorkerCount(); + + int getLargestWorkerCount(); +} diff --git a/server/sonar-server/src/test/java/org/sonar/server/async/AsyncExecutionMBeanImplTest.java b/server/sonar-server/src/test/java/org/sonar/server/async/AsyncExecutionMBeanImplTest.java new file mode 100644 index 00000000000..d4cbeb34320 --- /dev/null +++ b/server/sonar-server/src/test/java/org/sonar/server/async/AsyncExecutionMBeanImplTest.java @@ -0,0 +1,87 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program 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. + * + * This program 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.server.async; + +import java.lang.management.ManagementFactory; +import javax.annotation.CheckForNull; +import javax.management.InstanceNotFoundException; +import javax.management.ObjectInstance; +import javax.management.ObjectName; +import org.junit.Test; +import org.mockito.Mockito; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +public class AsyncExecutionMBeanImplTest { + private AsyncExecutionMonitoring asyncExecutionMonitoring = Mockito.mock(AsyncExecutionMonitoring.class); + + private AsyncExecutionMBeanImpl underTest = new AsyncExecutionMBeanImpl(asyncExecutionMonitoring); + + @Test + public void register_and_unregister() throws Exception { + assertThat(getMBean()).isNull(); + + underTest.start(); + assertThat(getMBean()).isNotNull(); + + underTest.stop(); + assertThat(getMBean()).isNull(); + } + + @Test + public void getQueueSize_delegates_to_AsyncExecutionMonitoring() { + when(asyncExecutionMonitoring.getQueueSize()).thenReturn(12); + + assertThat(underTest.getQueueSize()).isEqualTo(12); + + verify(asyncExecutionMonitoring).getQueueSize(); + } + + @Test + public void getWorkerCount_delegates_to_AsyncExecutionMonitoring() { + when(asyncExecutionMonitoring.getWorkerCount()).thenReturn(12); + + assertThat(underTest.getWorkerCount()).isEqualTo(12); + + verify(asyncExecutionMonitoring).getWorkerCount(); + } + + @Test + public void getLargestWorkerCount_delegates_to_AsyncExecutionMonitoring() { + when(asyncExecutionMonitoring.getLargestWorkerCount()).thenReturn(12); + + assertThat(underTest.getLargestWorkerCount()).isEqualTo(12); + + verify(asyncExecutionMonitoring).getLargestWorkerCount(); + } + + @CheckForNull + private ObjectInstance getMBean() throws Exception { + try { + return ManagementFactory.getPlatformMBeanServer().getObjectInstance(new ObjectName(AsyncExecutionMBean.OBJECT_NAME)); + } catch (InstanceNotFoundException e) { + return null; + } + } + + +} -- 2.39.5