From 3b05e9b82141482a588a56da496f0e8b65bd8f43 Mon Sep 17 00:00:00 2001 From: Daniel Schwarz Date: Fri, 18 Aug 2017 16:06:35 +0200 Subject: [PATCH] SONAR-9715 Implement pause mechanism during shutdown --- .../java/org/sonar/ce/ComputeEngineImpl.java | 9 ++++-- .../ce/container/ComputeEngineContainer.java | 2 ++ .../container/ComputeEngineContainerImpl.java | 11 ++++++- .../ce/container/ComputeEngineStatus.java | 32 +++++++++++++++++++ .../sonar/ce/queue/InternalCeQueueImpl.java | 7 ++-- .../org/sonar/ce/ComputeEngineImplTest.java | 5 +++ .../ComputeEngineContainerImplTest.java | 11 ++++++- .../ce/queue/InternalCeQueueImplTest.java | 16 +++++++++- 8 files changed, 85 insertions(+), 8 deletions(-) create mode 100644 server/sonar-ce/src/main/java/org/sonar/ce/container/ComputeEngineStatus.java diff --git a/server/sonar-ce/src/main/java/org/sonar/ce/ComputeEngineImpl.java b/server/sonar-ce/src/main/java/org/sonar/ce/ComputeEngineImpl.java index 4807acf5c12..c4067e7f7d7 100644 --- a/server/sonar-ce/src/main/java/org/sonar/ce/ComputeEngineImpl.java +++ b/server/sonar-ce/src/main/java/org/sonar/ce/ComputeEngineImpl.java @@ -19,12 +19,13 @@ */ package org.sonar.ce; +import org.sonar.ce.container.ComputeEngineStatus; import org.sonar.ce.container.ComputeEngineContainer; import org.sonar.process.Props; import static com.google.common.base.Preconditions.checkState; -public class ComputeEngineImpl implements ComputeEngine { +public class ComputeEngineImpl implements ComputeEngine, ComputeEngineStatus { private final Props props; private final ComputeEngineContainer computeEngineContainer; @@ -33,6 +34,7 @@ public class ComputeEngineImpl implements ComputeEngine { public ComputeEngineImpl(Props props, ComputeEngineContainer computeEngineContainer) { this.props = props; this.computeEngineContainer = computeEngineContainer; + computeEngineContainer.setComputeEngineStatus(this); } @Override @@ -63,7 +65,8 @@ public class ComputeEngineImpl implements ComputeEngine { checkState(currentStatus.ordinal() <= Status.STOPPING.ordinal(), "shutdown() can not be called multiple times"); } - private enum Status { - INIT, STARTING, STARTED, STOPPING, STOPPED + @Override + public Status getStatus() { + return status; } } diff --git a/server/sonar-ce/src/main/java/org/sonar/ce/container/ComputeEngineContainer.java b/server/sonar-ce/src/main/java/org/sonar/ce/container/ComputeEngineContainer.java index e395ff00306..acfc321c06f 100644 --- a/server/sonar-ce/src/main/java/org/sonar/ce/container/ComputeEngineContainer.java +++ b/server/sonar-ce/src/main/java/org/sonar/ce/container/ComputeEngineContainer.java @@ -22,6 +22,8 @@ package org.sonar.ce.container; import org.sonar.process.Props; public interface ComputeEngineContainer { + void setComputeEngineStatus(ComputeEngineStatus computeEngineStatus); + ComputeEngineContainer start(Props props); ComputeEngineContainer stop(); diff --git a/server/sonar-ce/src/main/java/org/sonar/ce/container/ComputeEngineContainerImpl.java b/server/sonar-ce/src/main/java/org/sonar/ce/container/ComputeEngineContainerImpl.java index eae580c3a3e..d89b83febaf 100644 --- a/server/sonar-ce/src/main/java/org/sonar/ce/container/ComputeEngineContainerImpl.java +++ b/server/sonar-ce/src/main/java/org/sonar/ce/container/ComputeEngineContainerImpl.java @@ -148,20 +148,29 @@ import org.sonar.server.view.index.ViewIndex; import org.sonar.server.view.index.ViewIndexer; import org.sonarqube.ws.Rules; +import static java.util.Objects.requireNonNull; + public class ComputeEngineContainerImpl implements ComputeEngineContainer { + private ComputeEngineStatus computeEngineStatus; @CheckForNull private ComponentContainer level1; @CheckForNull private ComponentContainer level4; + @Override + public void setComputeEngineStatus(ComputeEngineStatus computeEngineStatus) { + this.computeEngineStatus = computeEngineStatus; + } + @Override public ComputeEngineContainer start(Props props) { this.level1 = new ComponentContainer(); this.level1 .add(props.rawProperties()) .add(level1Components()) - .add(toArray(CorePropertyDefinitions.all())); + .add(toArray(CorePropertyDefinitions.all())) + .add(requireNonNull(computeEngineStatus)); configureFromModules(this.level1); this.level1.startComponents(); diff --git a/server/sonar-ce/src/main/java/org/sonar/ce/container/ComputeEngineStatus.java b/server/sonar-ce/src/main/java/org/sonar/ce/container/ComputeEngineStatus.java new file mode 100644 index 00000000000..600128e9bf6 --- /dev/null +++ b/server/sonar-ce/src/main/java/org/sonar/ce/container/ComputeEngineStatus.java @@ -0,0 +1,32 @@ +/* + * 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.container; + +public interface ComputeEngineStatus { + + /** + * This status will be consumed by multiple processes, hence the implementation of the method must be threadsafe + */ + Status getStatus(); + + enum Status { + INIT, STARTING, STARTED, STOPPING, STOPPED; + } +} diff --git a/server/sonar-ce/src/main/java/org/sonar/ce/queue/InternalCeQueueImpl.java b/server/sonar-ce/src/main/java/org/sonar/ce/queue/InternalCeQueueImpl.java index ee30acd613a..b3eb6dfde70 100644 --- a/server/sonar-ce/src/main/java/org/sonar/ce/queue/InternalCeQueueImpl.java +++ b/server/sonar-ce/src/main/java/org/sonar/ce/queue/InternalCeQueueImpl.java @@ -33,6 +33,7 @@ import org.apache.log4j.Logger; import org.sonar.api.ce.ComputeEngineSide; import org.sonar.api.utils.System2; import org.sonar.api.utils.log.Loggers; +import org.sonar.ce.container.ComputeEngineStatus; import org.sonar.ce.monitoring.CEQueueStatus; import org.sonar.core.util.UuidFactory; import org.sonar.db.DbClient; @@ -54,23 +55,25 @@ public class InternalCeQueueImpl extends CeQueueImpl implements InternalCeQueue private final System2 system2; private final DbClient dbClient; private final CEQueueStatus queueStatus; + private final ComputeEngineStatus computeEngineStatus; // state private AtomicBoolean peekPaused = new AtomicBoolean(false); public InternalCeQueueImpl(System2 system2, DbClient dbClient, UuidFactory uuidFactory, CEQueueStatus queueStatus, - DefaultOrganizationProvider defaultOrganizationProvider) { + DefaultOrganizationProvider defaultOrganizationProvider, ComputeEngineStatus computeEngineStatus) { super(dbClient, uuidFactory, defaultOrganizationProvider); this.system2 = system2; this.dbClient = dbClient; this.queueStatus = queueStatus; + this.computeEngineStatus = computeEngineStatus; } @Override public Optional peek(String workerUuid) { requireNonNull(workerUuid, "workerUuid can't be null"); - if (peekPaused.get()) { + if (peekPaused.get() || computeEngineStatus.getStatus() != ComputeEngineStatus.Status.STARTED) { return Optional.empty(); } try (DbSession dbSession = dbClient.openSession(false)) { diff --git a/server/sonar-ce/src/test/java/org/sonar/ce/ComputeEngineImplTest.java b/server/sonar-ce/src/test/java/org/sonar/ce/ComputeEngineImplTest.java index fc9528bed02..8a237a0169d 100644 --- a/server/sonar-ce/src/test/java/org/sonar/ce/ComputeEngineImplTest.java +++ b/server/sonar-ce/src/test/java/org/sonar/ce/ComputeEngineImplTest.java @@ -23,6 +23,7 @@ import java.util.Properties; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; +import org.sonar.ce.container.ComputeEngineStatus; import org.sonar.ce.container.ComputeEngineContainer; import org.sonar.process.Props; @@ -63,6 +64,10 @@ public class ComputeEngineImplTest { } private static class NoOpComputeEngineContainer implements ComputeEngineContainer { + @Override + public void setComputeEngineStatus(ComputeEngineStatus computeEngineStatus) { + } + @Override public ComputeEngineContainer start(Props props) { return this; diff --git a/server/sonar-ce/src/test/java/org/sonar/ce/container/ComputeEngineContainerImplTest.java b/server/sonar-ce/src/test/java/org/sonar/ce/container/ComputeEngineContainerImplTest.java index 89f8f852c59..3578e586c65 100644 --- a/server/sonar-ce/src/test/java/org/sonar/ce/container/ComputeEngineContainerImplTest.java +++ b/server/sonar-ce/src/test/java/org/sonar/ce/container/ComputeEngineContainerImplTest.java @@ -27,6 +27,7 @@ import java.util.Date; import java.util.Properties; import java.util.stream.Collectors; import org.apache.commons.dbcp.BasicDataSource; +import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TemporaryFolder; @@ -49,6 +50,7 @@ import org.sonar.process.Props; import static java.lang.String.valueOf; import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; import static org.sonar.process.ProcessEntryPoint.PROPERTY_PROCESS_INDEX; import static org.sonar.process.ProcessEntryPoint.PROPERTY_SHARED_PATH; import static org.sonar.process.ProcessProperties.PATH_DATA; @@ -65,7 +67,13 @@ public class ComputeEngineContainerImplTest { @Rule public DbTester dbTester = DbTester.create(System2.INSTANCE); - private ComputeEngineContainerImpl underTest = new ComputeEngineContainerImpl(); + private ComputeEngineContainerImpl underTest; + + @Before + public void setUp() throws Exception { + underTest = new ComputeEngineContainerImpl(); + underTest.setComputeEngineStatus(mock(ComputeEngineStatus.class)); + } @Test public void constructor_does_not_create_container() { @@ -139,6 +147,7 @@ public class ComputeEngineContainerImplTest { + 47 // content of DaoModule + 3 // content of EsSearchModule + 61 // content of CorePropertyDefinitions + + 1 // StopFlagContainer ); assertThat( picoContainer.getComponentAdapters().stream() diff --git a/server/sonar-ce/src/test/java/org/sonar/ce/queue/InternalCeQueueImplTest.java b/server/sonar-ce/src/test/java/org/sonar/ce/queue/InternalCeQueueImplTest.java index 84d7e2097bc..b133371f164 100644 --- a/server/sonar-ce/src/test/java/org/sonar/ce/queue/InternalCeQueueImplTest.java +++ b/server/sonar-ce/src/test/java/org/sonar/ce/queue/InternalCeQueueImplTest.java @@ -33,6 +33,7 @@ import org.junit.Test; import org.junit.rules.ExpectedException; import org.sonar.api.utils.System2; import org.sonar.api.utils.internal.AlwaysIncreasingSystem2; +import org.sonar.ce.container.ComputeEngineStatus; import org.sonar.ce.monitoring.CEQueueStatus; import org.sonar.ce.monitoring.CEQueueStatusImpl; import org.sonar.core.util.UuidFactory; @@ -53,6 +54,8 @@ import static java.util.Arrays.asList; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; +import static org.sonar.ce.container.ComputeEngineStatus.Status.STARTED; +import static org.sonar.ce.container.ComputeEngineStatus.Status.STOPPING; public class InternalCeQueueImplTest { @@ -72,7 +75,8 @@ public class InternalCeQueueImplTest { private UuidFactory uuidFactory = UuidFactoryImpl.INSTANCE; private CEQueueStatus queueStatus = new CEQueueStatusImpl(dbTester.getDbClient()); private DefaultOrganizationProvider defaultOrganizationProvider = mock(DefaultOrganizationProvider.class); - private InternalCeQueue underTest = new InternalCeQueueImpl(system2, dbTester.getDbClient(), uuidFactory, queueStatus, defaultOrganizationProvider); + private ComputeEngineStatus computeEngineStatus = mock(ComputeEngineStatus.class); + private InternalCeQueue underTest = new InternalCeQueueImpl(system2, dbTester.getDbClient(), uuidFactory, queueStatus, defaultOrganizationProvider, computeEngineStatus); @Before public void setUp() throws Exception { @@ -84,6 +88,7 @@ public class InternalCeQueueImplTest { .setCreatedAt(defaultOrganization.getCreatedAt()) .setUpdatedAt(defaultOrganization.getUpdatedAt()) .build()); + when(computeEngineStatus.getStatus()).thenReturn(STARTED); } @Test @@ -303,6 +308,15 @@ public class InternalCeQueueImplTest { assertThat(peek.isPresent()).isFalse(); } + @Test + public void peek_nothing_if_application_status_stopping() throws Exception { + submit(CeTaskTypes.REPORT, "PROJECT_1"); + when(computeEngineStatus.getStatus()).thenReturn(STOPPING); + + Optional peek = underTest.peek(WORKER_UUID_1); + assertThat(peek.isPresent()).isFalse(); + } + @Test public void peek_peeks_pending_tasks_with_executionCount_equal_to_0_and_increases_it() { dbTester.getDbClient().ceQueueDao().insert(session, new CeQueueDto() -- 2.39.5