diff --git a/monitor-worker-server/src/main/java/org/gridsuite/monitor/worker/server/orchestrator/StepExecutionService.java b/monitor-worker-server/src/main/java/org/gridsuite/monitor/worker/server/orchestrator/StepExecutionService.java index 0b560b39..a32b949f 100644 --- a/monitor-worker-server/src/main/java/org/gridsuite/monitor/worker/server/orchestrator/StepExecutionService.java +++ b/monitor-worker-server/src/main/java/org/gridsuite/monitor/worker/server/orchestrator/StepExecutionService.java @@ -6,6 +6,9 @@ */ package org.gridsuite.monitor.worker.server.orchestrator; +import com.powsybl.commons.PowsyblException; +import com.powsybl.commons.report.ReportNode; +import com.powsybl.commons.report.TypedValue; import lombok.RequiredArgsConstructor; import org.gridsuite.monitor.commons.types.messaging.ProcessExecutionStep; import org.gridsuite.monitor.commons.types.processconfig.ProcessConfig; @@ -33,6 +36,20 @@ public class StepExecutionService implements StepExecutor { private final Notificator notificationService; private final ReportRestClient reportRestClient; + private void handleException(ReportNode reportNode, Exception e) { + boolean isApplicationException = PowsyblException.class.isAssignableFrom(e.getClass()); + if (!isApplicationException && LOGGER.isErrorEnabled()) { + LOGGER.error(e.toString(), e); + } + String errorMessage = isApplicationException ? e.getMessage() : "Technical error: " + e; + + reportNode.newReportNode() + .withMessageTemplate("monitor.worker.server.step.error") + .withUntypedValue("errorMessage", errorMessage) + .withSeverity(TypedValue.ERROR_SEVERITY) + .add(); + } + @Override public void executeStep(StepWithContext stepWithContext) { ProcessStepExecutionContext context = stepWithContext.stepExecutionContext(); @@ -49,7 +66,8 @@ public void executeStep(StepWithContext stepWithCon throw e; } catch (Exception e) { status = StepStatus.FAILED; - throw new RuntimeException(e); + handleException(context.getReportNode(), e); + throw e; } finally { sendReportSafely(context); updateStepStatus(context, status); diff --git a/monitor-worker-server/src/main/java/org/gridsuite/monitor/worker/server/process/loadflow/steps/LoadflowRunComputationStep.java b/monitor-worker-server/src/main/java/org/gridsuite/monitor/worker/server/process/loadflow/steps/LoadflowRunComputationStep.java index 4d5dc302..45f596de 100644 --- a/monitor-worker-server/src/main/java/org/gridsuite/monitor/worker/server/process/loadflow/steps/LoadflowRunComputationStep.java +++ b/monitor-worker-server/src/main/java/org/gridsuite/monitor/worker/server/process/loadflow/steps/LoadflowRunComputationStep.java @@ -7,7 +7,6 @@ package org.gridsuite.monitor.worker.server.process.loadflow.steps; import com.powsybl.commons.report.ReportNode; -import com.powsybl.commons.report.TypedValue; import com.powsybl.loadflow.LoadFlow; import com.powsybl.loadflow.LoadFlowParameters; import com.powsybl.loadflow.LoadFlowResult; @@ -17,7 +16,6 @@ import org.gridsuite.monitor.commons.types.result.ResultType; import org.gridsuite.monitor.worker.server.clients.LoadFlowRestClient; import org.gridsuite.monitor.worker.server.core.context.ProcessStepExecutionContext; -import org.gridsuite.monitor.worker.server.core.exceptions.ProcessCancelledException; import org.gridsuite.monitor.worker.server.core.process.AbstractProcessStep; import org.gridsuite.monitor.worker.server.dto.parameters.loadflow.LoadFlowParametersInfos; import org.gridsuite.monitor.worker.server.orchestrator.TaskManager; @@ -27,7 +25,6 @@ import java.util.Objects; import java.util.UUID; -import java.util.concurrent.CancellationException; /** * @author Caroline Jeandat {@literal } @@ -50,27 +47,16 @@ public void execute(ProcessStepExecutionContext context) { ReportNode reportNode = context.getReportNode(); - try { - LoadFlowParametersInfos parametersInfos = loadflowRestClient.getParameters(context.getConfig().loadflowParametersUuid()); - LoadFlowParameters loadflowParameters = LoadFlowParametersService.buildParameters(parametersInfos); - LoadFlowRunParameters runParameters = new LoadFlowRunParameters() - .setParameters(loadflowParameters) - .setReportNode(reportNode); - LoadFlowResult result = taskManager.runComputation(context.getProcessExecutionId(), + LoadFlowParametersInfos parametersInfos = loadflowRestClient.getParameters(context.getConfig().loadflowParametersUuid()); + LoadFlowParameters loadflowParameters = LoadFlowParametersService.buildParameters(parametersInfos); + LoadFlowRunParameters runParameters = new LoadFlowRunParameters() + .setParameters(loadflowParameters) + .setReportNode(reportNode); + LoadFlowResult result = taskManager.runComputation(context.getProcessExecutionId(), () -> LoadFlow.find(parametersInfos.getProvider()).runAsync(context.getNetwork(), runParameters)); - UUID resultUuid = loadflowRestClient.saveResult(result); - ResultInfos resultInfos = new ResultInfos(resultUuid, ResultType.LOADFLOW); - context.setResultInfos(resultInfos); - } catch (CancellationException | ProcessCancelledException e) { - throw e; - } catch (Exception e) { - reportNode.newReportNode() - .withMessageTemplate("monitor.worker.server.loadflow.step.error") - .withUntypedValue("errorMessage", e.getMessage()) - .withSeverity(TypedValue.ERROR_SEVERITY) - .add(); - throw e; - } + UUID resultUuid = loadflowRestClient.saveResult(result); + ResultInfos resultInfos = new ResultInfos(resultUuid, ResultType.LOADFLOW); + context.setResultInfos(resultInfos); } } diff --git a/monitor-worker-server/src/main/java/org/gridsuite/monitor/worker/server/process/securityanalysis/steps/SecurityAnalysisRunComputationStep.java b/monitor-worker-server/src/main/java/org/gridsuite/monitor/worker/server/process/securityanalysis/steps/SecurityAnalysisRunComputationStep.java index 11255e3d..b2b7d6e1 100644 --- a/monitor-worker-server/src/main/java/org/gridsuite/monitor/worker/server/process/securityanalysis/steps/SecurityAnalysisRunComputationStep.java +++ b/monitor-worker-server/src/main/java/org/gridsuite/monitor/worker/server/process/securityanalysis/steps/SecurityAnalysisRunComputationStep.java @@ -7,7 +7,6 @@ package org.gridsuite.monitor.worker.server.process.securityanalysis.steps; import com.powsybl.commons.report.ReportNode; -import com.powsybl.commons.report.TypedValue; import com.powsybl.security.SecurityAnalysis; import com.powsybl.security.SecurityAnalysisReport; import com.powsybl.security.SecurityAnalysisRunParameters; @@ -16,16 +15,15 @@ import org.gridsuite.monitor.commons.types.result.ResultType; import org.gridsuite.monitor.worker.server.clients.SecurityAnalysisRestClient; import org.gridsuite.monitor.worker.server.core.context.ProcessStepExecutionContext; -import org.gridsuite.monitor.worker.server.core.exceptions.ProcessCancelledException; import org.gridsuite.monitor.worker.server.core.process.AbstractProcessStep; import org.gridsuite.monitor.worker.server.dto.parameters.securityanalysis.SecurityAnalysisInputData; import org.gridsuite.monitor.worker.server.orchestrator.TaskManager; import org.gridsuite.monitor.worker.server.process.securityanalysis.SecurityAnalysisStepType; import org.gridsuite.monitor.worker.server.services.SecurityAnalysisParametersService; import org.springframework.stereotype.Component; + import java.util.Objects; import java.util.UUID; -import java.util.concurrent.CancellationException; /** * @author Antoine Bouhours @@ -52,28 +50,17 @@ public void execute(ProcessStepExecutionContext context) ReportNode reportNode = context.getReportNode(); - try { - SecurityAnalysisInputData inputData = securityAnalysisParametersService.buildSecurityAnalysisInputData( - context.getConfig().securityAnalysisParametersUuid(), context.getConfig().loadflowParametersUuid(), context.getNetwork()); + SecurityAnalysisInputData inputData = securityAnalysisParametersService.buildSecurityAnalysisInputData( + context.getConfig().securityAnalysisParametersUuid(), context.getConfig().loadflowParametersUuid(), context.getNetwork()); - SecurityAnalysisRunParameters runParameters = new SecurityAnalysisRunParameters() - .setSecurityAnalysisParameters(inputData.securityAnalysisParameters()) - .setReportNode(reportNode); - SecurityAnalysisReport saReport = taskManager.runComputation(context.getProcessExecutionId(), + SecurityAnalysisRunParameters runParameters = new SecurityAnalysisRunParameters() + .setSecurityAnalysisParameters(inputData.securityAnalysisParameters()) + .setReportNode(reportNode); + SecurityAnalysisReport saReport = taskManager.runComputation(context.getProcessExecutionId(), () -> SecurityAnalysis.find(inputData.provider()).runAsync(context.getNetwork(), inputData.contingencies(), runParameters)); - ResultInfos resultInfos = new ResultInfos(UUID.randomUUID(), ResultType.SECURITY_ANALYSIS); - securityAnalysisRestClient.saveResult(resultInfos.resultUUID(), saReport.getResult()); - context.setResultInfos(resultInfos); - } catch (CancellationException | ProcessCancelledException e) { - throw e; - } catch (Exception e) { - reportNode.newReportNode() - .withMessageTemplate("monitor.worker.server.securityanalysis.step.error") - .withUntypedValue("errorMessage", e.getMessage()) - .withSeverity(TypedValue.ERROR_SEVERITY) - .add(); - throw e; - } + ResultInfos resultInfos = new ResultInfos(UUID.randomUUID(), ResultType.SECURITY_ANALYSIS); + securityAnalysisRestClient.saveResult(resultInfos.resultUUID(), saReport.getResult()); + context.setResultInfos(resultInfos); } } diff --git a/monitor-worker-server/src/main/java/org/gridsuite/monitor/worker/server/process/shortcircuit/steps/ShortCircuitRunComputationStep.java b/monitor-worker-server/src/main/java/org/gridsuite/monitor/worker/server/process/shortcircuit/steps/ShortCircuitRunComputationStep.java index d6252b3a..ce950db2 100644 --- a/monitor-worker-server/src/main/java/org/gridsuite/monitor/worker/server/process/shortcircuit/steps/ShortCircuitRunComputationStep.java +++ b/monitor-worker-server/src/main/java/org/gridsuite/monitor/worker/server/process/shortcircuit/steps/ShortCircuitRunComputationStep.java @@ -7,17 +7,17 @@ package org.gridsuite.monitor.worker.server.process.shortcircuit.steps; import com.powsybl.commons.PowsyblException; -import com.powsybl.commons.report.ReportNode; -import com.powsybl.commons.report.TypedValue; import com.powsybl.computation.local.LocalComputationManager; -import com.powsybl.shortcircuit.*; +import com.powsybl.shortcircuit.Fault; +import com.powsybl.shortcircuit.ShortCircuitAnalysis; +import com.powsybl.shortcircuit.ShortCircuitAnalysisResult; +import com.powsybl.shortcircuit.ShortCircuitParameters; import lombok.Getter; import org.gridsuite.monitor.commons.types.processconfig.ShortCircuitConfig; import org.gridsuite.monitor.commons.types.result.ResultInfos; import org.gridsuite.monitor.commons.types.result.ResultType; import org.gridsuite.monitor.worker.server.clients.ShortCircuitRestClient; import org.gridsuite.monitor.worker.server.core.context.ProcessStepExecutionContext; -import org.gridsuite.monitor.worker.server.core.exceptions.ProcessCancelledException; import org.gridsuite.monitor.worker.server.core.process.AbstractProcessStep; import org.gridsuite.monitor.worker.server.dto.parameters.shortcircuit.ShortCircuitParametersInfos; import org.gridsuite.monitor.worker.server.orchestrator.TaskManager; @@ -35,7 +35,6 @@ import java.util.Map; import java.util.Objects; import java.util.UUID; -import java.util.concurrent.CancellationException; /** * @author Caroline Jeandat {@literal } @@ -72,29 +71,16 @@ public ShortCircuitRunComputationStep( public void execute(ProcessStepExecutionContext context) { Objects.requireNonNull(context.getNetwork()); - ReportNode reportNode = context.getReportNode(); + ShortCircuitParametersInfos parametersInfos = shortCircuitRestClient.getParameters(context.getConfig().shortCircuitParametersUuid()); + // TODO: in shortcircuit-server, retrieved parameters are post processed before being passed to the short-circuit calculation - try { - ShortCircuitParametersInfos parametersInfos = shortCircuitRestClient.getParameters(context.getConfig().shortCircuitParametersUuid()); - // TODO: in shortcircuit-server, retrieved parameters are post processed before being passed to the short-circuit calculation - - String provider = parametersInfos.getProvider() != null ? parametersInfos.getProvider() : getDefaultProvider(); - Map specificParameters = parametersInfos.getSpecificParametersPerProvider().get(provider); - ShortCircuitParameters commonParameters = shortCircuitParametersService.buildParameters(parametersInfos, provider, specificParameters); - if (context.getDebugFileLocation() == null) { - runComputation(context, provider, commonParameters, specificParameters); - } else { - runComputationWithDebug(context, provider, commonParameters, specificParameters); - } - } catch (CancellationException | ProcessCancelledException e) { - throw e; - } catch (Exception e) { - reportNode.newReportNode() - .withMessageTemplate("monitor.worker.server.shortcircuit.step.error") - .withUntypedValue("errorMessage", e.getMessage()) - .withSeverity(TypedValue.ERROR_SEVERITY) - .add(); - throw e; + String provider = parametersInfos.getProvider() != null ? parametersInfos.getProvider() : getDefaultProvider(); + Map specificParameters = parametersInfos.getSpecificParametersPerProvider().get(provider); + ShortCircuitParameters commonParameters = shortCircuitParametersService.buildParameters(parametersInfos, provider, specificParameters); + if (context.getDebugFileLocation() == null) { + runComputation(context, provider, commonParameters, specificParameters); + } else { + runComputationWithDebug(context, provider, commonParameters, specificParameters); } } diff --git a/monitor-worker-server/src/main/resources/org/gridsuite/monitor/worker/server/reports.properties b/monitor-worker-server/src/main/resources/org/gridsuite/monitor/worker/server/reports.properties index 056a52eb..70b545fe 100644 --- a/monitor-worker-server/src/main/resources/org/gridsuite/monitor/worker/server/reports.properties +++ b/monitor-worker-server/src/main/resources/org/gridsuite/monitor/worker/server/reports.properties @@ -1,9 +1,7 @@ monitor.worker.server.importCase = Import Case : ${caseName} -monitor.worker.server.loadflow.step.error = ${errorMessage} monitor.worker.server.modifications.error = Some network composite modifications are missing : ${uuids} monitor.worker.server.modifications.not.applied = Some network composite modifications are not applied intentionally (see process-config) : ${uuids} monitor.worker.server.process = Process execution id : ${executionId} -monitor.worker.server.securityanalysis.step.error = ${errorMessage} -monitor.worker.server.shortcircuit.step.error = ${errorMessage} monitor.worker.server.shortcircuit.step.error.VoltageLevelsWithWrongIscValuesSummarize = Some voltage levels have wrong isc values, isc min must be <= isc max: ${voltageLevels} +monitor.worker.server.step.error = ${errorMessage} monitor.worker.server.stepType = ${stepType} diff --git a/monitor-worker-server/src/main/resources/org/gridsuite/monitor/worker/server/reports_fr.properties b/monitor-worker-server/src/main/resources/org/gridsuite/monitor/worker/server/reports_fr.properties index 056a52eb..70b545fe 100644 --- a/monitor-worker-server/src/main/resources/org/gridsuite/monitor/worker/server/reports_fr.properties +++ b/monitor-worker-server/src/main/resources/org/gridsuite/monitor/worker/server/reports_fr.properties @@ -1,9 +1,7 @@ monitor.worker.server.importCase = Import Case : ${caseName} -monitor.worker.server.loadflow.step.error = ${errorMessage} monitor.worker.server.modifications.error = Some network composite modifications are missing : ${uuids} monitor.worker.server.modifications.not.applied = Some network composite modifications are not applied intentionally (see process-config) : ${uuids} monitor.worker.server.process = Process execution id : ${executionId} -monitor.worker.server.securityanalysis.step.error = ${errorMessage} -monitor.worker.server.shortcircuit.step.error = ${errorMessage} monitor.worker.server.shortcircuit.step.error.VoltageLevelsWithWrongIscValuesSummarize = Some voltage levels have wrong isc values, isc min must be <= isc max: ${voltageLevels} +monitor.worker.server.step.error = ${errorMessage} monitor.worker.server.stepType = ${stepType} diff --git a/monitor-worker-server/src/test/java/org/gridsuite/monitor/worker/server/orchestrator/StepExecutionServiceTest.java b/monitor-worker-server/src/test/java/org/gridsuite/monitor/worker/server/orchestrator/StepExecutionServiceTest.java index 08fd7b8b..e8090e75 100644 --- a/monitor-worker-server/src/test/java/org/gridsuite/monitor/worker/server/orchestrator/StepExecutionServiceTest.java +++ b/monitor-worker-server/src/test/java/org/gridsuite/monitor/worker/server/orchestrator/StepExecutionServiceTest.java @@ -19,6 +19,7 @@ import org.gridsuite.monitor.worker.server.core.process.ProcessStep; import org.gridsuite.monitor.worker.server.core.process.ProcessStepType; import org.gridsuite.monitor.worker.server.messaging.NotificationService; +import org.gridsuite.monitor.worker.server.utils.ReportTestUtils; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -32,6 +33,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.*; @@ -120,7 +122,7 @@ void executeStepShouldCompleteSuccessfullyWhenReportSendingFails() { } @Test - void executeStepShouldSendFailedStatusWhenExceptionThrown() { + void executeStepShouldSendFailedStatusAndReportErrorWhenExceptionThrown() { UUID executionId = UUID.randomUUID(); UUID processReportId = UUID.randomUUID(); int stepOrder = 2; @@ -134,7 +136,10 @@ void executeStepShouldSendFailedStatusWhenExceptionThrown() { RuntimeException.class, () -> stepExecutionService.executeStep(stepWithContext) ); - assertEquals("Step execution failed", thrownException.getCause().getMessage()); + + assertTrue(ReportTestUtils.assertMessageFoundFromReporter("Technical error: java.lang.RuntimeException: Step execution failed", "monitor.worker.server.step.error", context.getReportNode())); + assertEquals("Step execution failed", thrownException.getMessage()); + verify(notificationService, times(2)).updateStepStatus(eq(executionId), eq(ProcessType.SECURITY_ANALYSIS), any(ProcessExecutionStep.class)); InOrder inOrder = inOrder(notificationService); inOrder.verify(notificationService).updateStepStatus(eq(executionId), eq(ProcessType.SECURITY_ANALYSIS), argThat(step -> diff --git a/monitor-worker-server/src/test/java/org/gridsuite/monitor/worker/server/process/shortcircuit/steps/ShortCircuitRunComputationStepTest.java b/monitor-worker-server/src/test/java/org/gridsuite/monitor/worker/server/process/shortcircuit/steps/ShortCircuitRunComputationStepTest.java index 9967dcfb..95624696 100644 --- a/monitor-worker-server/src/test/java/org/gridsuite/monitor/worker/server/process/shortcircuit/steps/ShortCircuitRunComputationStepTest.java +++ b/monitor-worker-server/src/test/java/org/gridsuite/monitor/worker/server/process/shortcircuit/steps/ShortCircuitRunComputationStepTest.java @@ -92,12 +92,6 @@ void setUp() { when(stepContext.getConfig()).thenReturn(config); when(config.shortCircuitParametersUuid()).thenReturn(PARAMS_UUID); - - ReportNode reportNode = ReportNode.newRootReportNode() - .withResourceBundles("i18n.reports") - .withMessageTemplate("test") - .build(); - when(stepContext.getReportNode()).thenReturn(reportNode); } @Test @@ -238,6 +232,12 @@ private void assertCancellationDoesNotReportFailure(RuntimeException cancellatio runComputationStep = new ShortCircuitRunComputationStep( shortCircuitParametersService, shortCircuitRestClient, s3Service, fileService, taskManager, "ShortCircuit-provider"); when(stepContext.getProcessExecutionId()).thenReturn(executionId); + when(stepContext.getConfig()).thenReturn(config); + ReportNode reportNode = ReportNode.newRootReportNode() + .withResourceBundles("i18n.reports") + .withMessageTemplate("test") + .build(); + when(stepContext.getReportNode()).thenReturn(reportNode); Network network = EurostagTutorialExample1Factory.create(); when(stepContext.getNetwork()).thenReturn(network); ShortCircuitParameters parameters = new ShortCircuitParameters(); diff --git a/monitor-worker-server/src/test/java/org/gridsuite/monitor/worker/server/utils/ReportTestUtils.java b/monitor-worker-server/src/test/java/org/gridsuite/monitor/worker/server/utils/ReportTestUtils.java new file mode 100644 index 00000000..a5d28591 --- /dev/null +++ b/monitor-worker-server/src/test/java/org/gridsuite/monitor/worker/server/utils/ReportTestUtils.java @@ -0,0 +1,43 @@ +/** + * Copyright (c) 2026, RTE (http://www.rte-france.com) + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +package org.gridsuite.monitor.worker.server.utils; + +import com.powsybl.commons.report.ReportNode; +import org.apache.commons.text.StringSubstitutor; + +/** + * @author Franck Lecuyer + */ +public final class ReportTestUtils { + private ReportTestUtils() { + throw new IllegalCallerException("Utility class"); + } + + public static boolean assertMessageFoundFromReporter(String expectedMessage, String reportKey, ReportNode reporterModel) { + StringSubstitutor reporterSubstitutor = new StringSubstitutor(reporterModel.getValues()); + return containsMessage(expectedMessage, reportKey, reporterModel, reporterSubstitutor); + } + + private static boolean containsMessage(String expectedMessage, String reportKey, ReportNode reporter, StringSubstitutor reporterSubstitutor) { + for (ReportNode child : reporter.getChildren()) { + if (reportKey.equals(child.getMessageKey()) && expectedMessage.equals(formatReportMessage(child, reporterSubstitutor))) { + return true; + } + StringSubstitutor childSubstitutor = new StringSubstitutor(child.getValues()); + if (containsMessage(expectedMessage, reportKey, child, childSubstitutor)) { + return true; + } + } + return false; + } + + private static String formatReportMessage(ReportNode report, StringSubstitutor reporterSubstitutor) { + String reportMessage = new StringSubstitutor(report.getValues()).replace(report.getMessageTemplate()); + return reporterSubstitutor.replace(reportMessage).trim(); + } +} +