From 351132a0cd30ff6ae33ff9def57191e3d180b9d5 Mon Sep 17 00:00:00 2001 From: Joris Mancini Date: Fri, 13 Dec 2024 18:06:47 +0100 Subject: [PATCH 1/3] feat: rely on rabbitmq dlq for computation errors handling Signed-off-by: Joris Mancini --- pom.xml | 6 +- .../notification/NotificationService.java | 2 - .../impl/NotificationServiceImpl.java | 5 -- src/main/resources/config/application.yaml | 16 +++- ...stractDynamicSimulationControllerTest.java | 4 +- .../DynamicSimulationControllerTest.java | 75 +++---------------- 6 files changed, 29 insertions(+), 79 deletions(-) diff --git a/pom.xml b/pom.xml index 4208cbfe..8b7c67a3 100644 --- a/pom.xml +++ b/pom.xml @@ -87,7 +87,11 @@ - + + com.powsybl + powsybl-ws-commons + 1.19.0-SNAPSHOT + org.gridsuite diff --git a/src/main/java/org/gridsuite/ds/server/service/notification/NotificationService.java b/src/main/java/org/gridsuite/ds/server/service/notification/NotificationService.java index 8d68da58..4aa7a6cd 100644 --- a/src/main/java/org/gridsuite/ds/server/service/notification/NotificationService.java +++ b/src/main/java/org/gridsuite/ds/server/service/notification/NotificationService.java @@ -20,6 +20,4 @@ public interface NotificationService { void emitResultDynamicSimulationMessage(Message message); void emitCancelDynamicSimulationMessage(Message message); - - void emitFailDynamicSimulationMessage(Message message); } diff --git a/src/main/java/org/gridsuite/ds/server/service/notification/impl/NotificationServiceImpl.java b/src/main/java/org/gridsuite/ds/server/service/notification/impl/NotificationServiceImpl.java index 86b9ff7c..4dc55dec 100644 --- a/src/main/java/org/gridsuite/ds/server/service/notification/impl/NotificationServiceImpl.java +++ b/src/main/java/org/gridsuite/ds/server/service/notification/impl/NotificationServiceImpl.java @@ -44,9 +44,4 @@ public void emitResultDynamicSimulationMessage(Message message) { public void emitCancelDynamicSimulationMessage(Message message) { sendMessage(message, "publishCancel-out-0"); } - - @Override - public void emitFailDynamicSimulationMessage(Message message) { - sendMessage(message, "publishFailed-out-0"); - } } diff --git a/src/main/resources/config/application.yaml b/src/main/resources/config/application.yaml index 3943c533..30e0e28b 100644 --- a/src/main/resources/config/application.yaml +++ b/src/main/resources/config/application.yaml @@ -12,6 +12,7 @@ spring: group: dsGroup consumer: concurrency: 2 + max-attempts: 1 publishRun-out-0: destination: ${powsybl-ws.rabbitmq.destination.prefix:}ds.run publishResult-out-0: @@ -22,11 +23,20 @@ spring: destination: ${powsybl-ws.rabbitmq.destination.prefix:}ds.cancel publishStopped-out-0: destination: ${powsybl-ws.rabbitmq.destination.prefix:}ds.stopped - publishFailed-out-0: - destination: ${powsybl-ws.rabbitmq.destination.prefix:}ds.failed publishCancelFailed-out-0: destination: ${powsybl-ws.rabbitmq.destination.prefix:}ds.cancelfailed - output-bindings: publishRun-out-0;publishResult-out-0;publishCancel-out-0;publishStopped-out-0;publishFailed-out-0;publishCancelFailed-out-0 + output-bindings: publishRun-out-0;publishResult-out-0;publishCancel-out-0;publishStopped-out-0;publishCancelFailed-out-0 + rabbit: + bindings: + consumeRun-in-0: + consumer: + auto-bind-dlq: true + dead-letter-exchange: ${powsybl-ws.rabbitmq.destination.prefix:}ds.run.dlx + dead-letter-queue-name: ${powsybl-ws.rabbitmq.destination.prefix:}ds.run.dlx.dlq + dead-letter-exchange-type: topic + quorum: + enabled: true + delivery-limit: 2 powsybl: services: diff --git a/src/test/java/org/gridsuite/ds/server/controller/AbstractDynamicSimulationControllerTest.java b/src/test/java/org/gridsuite/ds/server/controller/AbstractDynamicSimulationControllerTest.java index 630ab517..7b257475 100644 --- a/src/test/java/org/gridsuite/ds/server/controller/AbstractDynamicSimulationControllerTest.java +++ b/src/test/java/org/gridsuite/ds/server/controller/AbstractDynamicSimulationControllerTest.java @@ -45,7 +45,7 @@ public abstract class AbstractDynamicSimulationControllerTest extends AbstractDy protected final Logger logger = LoggerFactory.getLogger(this.getClass()); protected final String dsResultDestination = "ds.result.destination"; - protected final String dsFailedDestination = "ds.failed.destination"; + protected final String dsFailedDestination = "ds.run.dlx"; protected final String dsStoppedDestination = "ds.stopped.destination"; protected final String dsCancelFailedDestination = "ds.cancelfailed.destination"; @@ -85,7 +85,7 @@ public void tearDown() throws Exception { super.tearDown(); OutputDestination output = getOutputDestination(); - List destinations = List.of(dsFailedDestination, dsResultDestination, dsStoppedDestination, dsCancelFailedDestination); + List destinations = List.of(dsResultDestination, dsStoppedDestination, dsCancelFailedDestination); try { TestUtils.assertQueuesEmptyThenClear(destinations, output); diff --git a/src/test/java/org/gridsuite/ds/server/controller/DynamicSimulationControllerTest.java b/src/test/java/org/gridsuite/ds/server/controller/DynamicSimulationControllerTest.java index 384bd233..6859f398 100644 --- a/src/test/java/org/gridsuite/ds/server/controller/DynamicSimulationControllerTest.java +++ b/src/test/java/org/gridsuite/ds/server/controller/DynamicSimulationControllerTest.java @@ -152,32 +152,6 @@ public void tearDown() throws Exception { .andExpect(status().isOk()); } - @Test - public void testGivenNotExistingNetworkUuid() throws Exception { - - // mock NetworkStoreService throws exception for a none-existing network uuid - given(networkStoreClient.getNetwork(UUID.fromString(NETWORK_UUID_NOT_FOUND_STRING), PreloadingStrategy.COLLECTION)).willThrow(new PowsyblException()); - - // prepare parameters - DynamicSimulationParametersInfos parameters = ParameterUtils.getDefaultDynamicSimulationParameters(); - - // network not found - MvcResult result = mockMvc.perform( - post("/v1/networks/{networkUuid}/run?" + "&mappingName=" + MAPPING_NAME, NETWORK_UUID_NOT_FOUND_STRING) - .contentType(APPLICATION_JSON) - .header(HEADER_USER_ID, "testUserId") - .content(objectMapper.writeValueAsString(parameters))) - .andExpect(status().isOk()) - .andReturn(); - - UUID runUuid = objectMapper.readValue(result.getResponse().getContentAsString(), UUID.class); - - Message messageSwitch = output.receive(1000 * 5, dsFailedDestination); - assertThat(messageSwitch.getHeaders()).containsEntry(HEADER_RESULT_UUID, runUuid.toString()); - assertThat(Objects.requireNonNull(messageSwitch.getHeaders().get(HEADER_MESSAGE)).toString()) - .contains(getFailedMessage(COMPUTATION_TYPE)); - } - @Test public void testGivenTimeSeriesAndTimeLine() throws Exception { @@ -376,37 +350,6 @@ public void testGivenEmptyTimeSeriesAndTimeLine() throws Exception { } - @Test - public void testGivenRunWithException() throws Exception { - // setup spy bean - doAnswer((InvocationOnMock invocation) -> CompletableFuture.supplyAsync(() -> { - throw new RuntimeException(TEST_EXCEPTION_MESSAGE); - })) - .when(dynamicSimulationWorkerService).getCompletableFuture(any(), any(), any()); - - // prepare parameters - DynamicSimulationParametersInfos parameters = ParameterUtils.getDefaultDynamicSimulationParameters(); - - //run the dynamic simulation - MvcResult result = mockMvc.perform( - post("/v1/networks/{networkUuid}/run?" + "&mappingName=" + MAPPING_NAME, NETWORK_UUID_STRING) - .contentType(APPLICATION_JSON) - .header(HEADER_USER_ID, "testUserId") - .content(objectMapper.writeValueAsString(parameters))) - .andExpect(status().isOk()) - .andReturn(); - - UUID runUuid = objectMapper.readValue(result.getResponse().getContentAsString(), UUID.class); - - // Message failed must be sent - Message messageSwitch = output.receive(1000, dsFailedDestination); - - // check uuid and failed message - assertThat(messageSwitch.getHeaders()).containsEntry(HEADER_RESULT_UUID, runUuid.toString()); - assertThat(Objects.requireNonNull(messageSwitch.getHeaders().get(HEADER_MESSAGE)).toString()) - .contains(TEST_EXCEPTION_MESSAGE); - } - // --- BEGIN Test cancelling a running computation ---// private void mockSendRunMessage(Supplier> runAsyncMock) { // In test environment, the test binder calls consumers directly in the caller thread, i.e. the controller thread. @@ -539,13 +482,13 @@ public void testStopEarly() throws Exception { UUID runUuid = runAndCancel(cancelLatch, 0); // check result - // Must have a cancel failed message in the queue - Message message = output.receive(1000, dsCancelFailedDestination); + // Must have a stopped message in the queue + Message message = output.receive(1000, dsStoppedDestination); assertThat(message.getHeaders()) .containsEntry(HEADER_RESULT_UUID, runUuid.toString()) - .containsEntry(HEADER_MESSAGE, getCancelFailedMessage(COMPUTATION_TYPE)); - // cancel failed so result still exist - assertResultStatus(runUuid, status().isOk()); + .containsEntry(HEADER_MESSAGE, getCancelMessage(COMPUTATION_TYPE)); + // cancel succeeded so result still exist + assertNotFoundResult(runUuid); } @Test @@ -572,12 +515,12 @@ public void testStopLately() throws Exception { .containsEntry(HEADER_RESULT_UUID, runUuid.toString()); // Must have a cancel failed message in the queue - message = output.receive(1000, dsCancelFailedDestination); + message = output.receive(1000, dsStoppedDestination); assertThat(message.getHeaders()) .containsEntry(HEADER_RESULT_UUID, runUuid.toString()) - .containsEntry(HEADER_MESSAGE, getCancelFailedMessage(COMPUTATION_TYPE)); - // cancel failed so results are not deleted - assertResultStatus(runUuid, status().isOk()); + .containsEntry(HEADER_MESSAGE, getCancelMessage(COMPUTATION_TYPE)); + // cancel succeeded so results are not deleted + assertNotFoundResult(runUuid); } // --- END Test cancelling a running computation ---// From 78fa5817faa43bcd4f7dd4e5f3d4cb08012cf94b Mon Sep 17 00:00:00 2001 From: Joris Mancini Date: Fri, 20 Dec 2024 10:18:30 +0100 Subject: [PATCH 2/3] fix: tests Signed-off-by: Joris Mancini --- ...stractDynamicSimulationControllerTest.java | 1 - .../DynamicSimulationControllerTest.java | 20 +++++++++---------- 2 files changed, 9 insertions(+), 12 deletions(-) diff --git a/src/test/java/org/gridsuite/ds/server/controller/AbstractDynamicSimulationControllerTest.java b/src/test/java/org/gridsuite/ds/server/controller/AbstractDynamicSimulationControllerTest.java index 7b257475..b83fb8cc 100644 --- a/src/test/java/org/gridsuite/ds/server/controller/AbstractDynamicSimulationControllerTest.java +++ b/src/test/java/org/gridsuite/ds/server/controller/AbstractDynamicSimulationControllerTest.java @@ -45,7 +45,6 @@ public abstract class AbstractDynamicSimulationControllerTest extends AbstractDy protected final Logger logger = LoggerFactory.getLogger(this.getClass()); protected final String dsResultDestination = "ds.result.destination"; - protected final String dsFailedDestination = "ds.run.dlx"; protected final String dsStoppedDestination = "ds.stopped.destination"; protected final String dsCancelFailedDestination = "ds.cancelfailed.destination"; diff --git a/src/test/java/org/gridsuite/ds/server/controller/DynamicSimulationControllerTest.java b/src/test/java/org/gridsuite/ds/server/controller/DynamicSimulationControllerTest.java index 6859f398..a7c2e789 100644 --- a/src/test/java/org/gridsuite/ds/server/controller/DynamicSimulationControllerTest.java +++ b/src/test/java/org/gridsuite/ds/server/controller/DynamicSimulationControllerTest.java @@ -7,7 +7,6 @@ package org.gridsuite.ds.server.controller; import com.fasterxml.jackson.databind.ObjectMapper; -import com.powsybl.commons.PowsyblException; import com.powsybl.commons.datasource.ReadOnlyDataSource; import com.powsybl.commons.datasource.ResourceDataSource; import com.powsybl.commons.datasource.ResourceSet; @@ -33,7 +32,6 @@ import org.junit.Test; import org.mockito.MockedStatic; import org.mockito.Mockito; -import org.mockito.invocation.InvocationOnMock; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.mock.mockito.SpyBean; import org.springframework.cloud.stream.binder.test.InputDestination; @@ -482,13 +480,13 @@ public void testStopEarly() throws Exception { UUID runUuid = runAndCancel(cancelLatch, 0); // check result - // Must have a stopped message in the queue - Message message = output.receive(1000, dsStoppedDestination); + // Must have a cancel failed message in the queue + Message message = output.receive(1000, dsCancelFailedDestination); assertThat(message.getHeaders()) .containsEntry(HEADER_RESULT_UUID, runUuid.toString()) - .containsEntry(HEADER_MESSAGE, getCancelMessage(COMPUTATION_TYPE)); - // cancel succeeded so result still exist - assertNotFoundResult(runUuid); + .containsEntry(HEADER_MESSAGE, getCancelFailedMessage(COMPUTATION_TYPE)); + // cancel failed so result still exist + assertResultStatus(runUuid, status().isOk()); } @Test @@ -515,12 +513,12 @@ public void testStopLately() throws Exception { .containsEntry(HEADER_RESULT_UUID, runUuid.toString()); // Must have a cancel failed message in the queue - message = output.receive(1000, dsStoppedDestination); + message = output.receive(1000, dsCancelFailedDestination); assertThat(message.getHeaders()) .containsEntry(HEADER_RESULT_UUID, runUuid.toString()) - .containsEntry(HEADER_MESSAGE, getCancelMessage(COMPUTATION_TYPE)); - // cancel succeeded so results are not deleted - assertNotFoundResult(runUuid); + .containsEntry(HEADER_MESSAGE, getCancelFailedMessage(COMPUTATION_TYPE)); + // cancel failed so results are not deleted + assertResultStatus(runUuid, status().isOk()); } // --- END Test cancelling a running computation ---// From 1f38a4ee24bd323ede681509f72e89ca27250068 Mon Sep 17 00:00:00 2001 From: Joris Mancini <53527338+TheMaskedTurtle@users.noreply.github.com> Date: Fri, 20 Dec 2024 11:31:45 +0100 Subject: [PATCH 3/3] Bump powsybl-ws-commons to 1.19.0 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 8b7c67a3..b4ce9782 100644 --- a/pom.xml +++ b/pom.xml @@ -87,10 +87,10 @@ - + com.powsybl powsybl-ws-commons - 1.19.0-SNAPSHOT + 1.19.0