-
Notifications
You must be signed in to change notification settings - Fork 1
POC : use existing servers to run cyclic chain #47
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
b0866ac
24999ae
4bd069d
f52b58e
1221e18
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,38 @@ | ||
| /** | ||
| * 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.commons; | ||
|
|
||
| import lombok.Getter; | ||
|
|
||
| import java.util.UUID; | ||
|
|
||
| /** | ||
| * @author Franck Lecuyer <franck.lecuyer at rte-france.com> | ||
| */ | ||
| @Getter | ||
| public class CaseResultInfos { | ||
| private final UUID caseResultUuid; | ||
|
|
||
| private final UUID executionUuid; | ||
|
|
||
| private final UUID reportUuid; | ||
|
|
||
| private final UUID resultUuid; | ||
|
|
||
| private final String stepType; | ||
|
|
||
| private final String status; | ||
|
|
||
| public CaseResultInfos(UUID caseResultUuid, UUID executionUuid, UUID reportUuid, UUID resultUuid, String stepType, String status) { | ||
| this.caseResultUuid = caseResultUuid; | ||
| this.executionUuid = executionUuid; | ||
| this.reportUuid = reportUuid; | ||
| this.resultUuid = resultUuid; | ||
| this.stepType = stepType; | ||
| this.status = status; | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,167 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * 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.server.services; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import org.gridsuite.monitor.commons.CaseResultInfos; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import org.gridsuite.monitor.commons.ProcessConfig; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import org.gridsuite.monitor.commons.ProcessExecutionStep; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import org.gridsuite.monitor.commons.ProcessRunMessage; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import org.gridsuite.monitor.commons.ProcessStatus; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import org.gridsuite.monitor.commons.ResultType; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import org.gridsuite.monitor.commons.SecurityAnalysisConfig; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import org.gridsuite.monitor.commons.StepStatus; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import org.slf4j.Logger; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import org.slf4j.LoggerFactory; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import org.springframework.beans.factory.annotation.Autowired; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import org.springframework.context.annotation.Bean; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import org.springframework.context.annotation.Configuration; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import org.springframework.messaging.Message; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import java.time.Instant; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import java.util.List; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import java.util.Map; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import java.util.UUID; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import java.util.concurrent.ConcurrentHashMap; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import java.util.function.Consumer; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * @author Franck Lecuyer <franck.lecuyer at rte-france.com> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| @Configuration | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| public class ConsumerServiceUsingServers { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private static final Logger LOGGER = LoggerFactory.getLogger(ConsumerServiceUsingServers.class); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private final NetworkModificationRestService networkModificationRestService; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private final SecurityAnalysisRestService securityAnalysisRestService; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private final MonitorService monitorService; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private record ProcessExecutionContext( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| UUID applyModificationsStepId, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| UUID securityAnalysisStepId, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| UUID caseUuid, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| List<String> contingencies, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| UUID parametersUuid | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) { } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private final Map<UUID, ProcessExecutionContext> processExecutionContexts = new ConcurrentHashMap<>(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| @Autowired | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ConsumerServiceUsingServers(NetworkModificationRestService networkModificationRestService, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| SecurityAnalysisRestService securityAnalysisRestService, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| MonitorService monitorService) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| this.networkModificationRestService = networkModificationRestService; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| this.securityAnalysisRestService = securityAnalysisRestService; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| this.monitorService = monitorService; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| @Bean | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| public <T extends ProcessConfig> Consumer<Message<ProcessRunMessage<T>>> consumeRunUsingServers() { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // consume message to launch process | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return message -> { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ProcessRunMessage<T> processRunMessage = message.getPayload(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| UUID caseUuid = processRunMessage.caseUuid(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| UUID executionId = processRunMessage.executionId(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ProcessConfig processConfig = processRunMessage.config(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| List<UUID> modificationUuids = ((SecurityAnalysisConfig) processConfig).modificationUuids(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| UUID applyModificationsStepId = UUID.randomUUID(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| UUID securityAnalysisStepId = UUID.randomUUID(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| List<String> contingencies = null; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| UUID parametersUuid = null; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| switch (processConfig.processType()) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Check warning on line 78 in monitor-server/src/main/java/org/gridsuite/monitor/server/services/ConsumerServiceUsingServers.java
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| case SECURITY_ANALYSIS -> { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| contingencies = ((SecurityAnalysisConfig) processConfig).contingencies(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| parametersUuid = ((SecurityAnalysisConfig) processConfig).parametersUuid(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| processExecutionContexts.put(executionId, new ProcessExecutionContext( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| applyModificationsStepId, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| securityAnalysisStepId, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| caseUuid, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| contingencies, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| parametersUuid | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| )); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| monitorService.updateExecutionStatus(executionId, ProcessStatus.RUNNING, null, Instant.now(), null); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| monitorService.updateStepStatus(executionId, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| new ProcessExecutionStep(applyModificationsStepId, "APPLY_MODIFICATIONS", 0, StepStatus.RUNNING, null, null, null, Instant.now(), null, null)); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| monitorService.updateStepStatus(executionId, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| new ProcessExecutionStep(securityAnalysisStepId, "SECURITY_ANALYSIS", 1, StepStatus.SCHEDULED, null, null, null, null, null, null)); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // call network-modification-server to apply modifications | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| networkModificationRestService.applyModifications(caseUuid, executionId, modificationUuids); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+99
to
+100
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Handle REST client failures to avoid stuck RUNNING executions. Lines 99-100 and 132 call external services without exception handling. If either call throws, execution state can remain inconsistent and context may leak. 🧯 Proposed fix- networkModificationRestService.applyModifications(caseUuid, executionId, modificationUuids);
+ try {
+ networkModificationRestService.applyModifications(caseUuid, executionId, modificationUuids);
+ } catch (RuntimeException ex) {
+ LOGGER.error("applyModifications failed for executionId: {}", executionId, ex);
+ monitorService.updateExecutionStatus(executionId, ProcessStatus.FAILED, null, null, Instant.now());
+ processExecutionContexts.remove(executionId);
+ }
...
if (stepStatus == StepStatus.COMPLETED) {
// call security-analysis-server to run security analysis
- securityAnalysisRestService.runSecurityAnalysis(caseResultUuid, executionId, processExecutionContext.contingencies(), processExecutionContext.parametersUuid());
+ try {
+ securityAnalysisRestService.runSecurityAnalysis(caseResultUuid, executionId, processExecutionContext.contingencies(), processExecutionContext.parametersUuid());
+ } catch (RuntimeException ex) {
+ LOGGER.error("runSecurityAnalysis failed for executionId: {}", executionId, ex);
+ monitorService.updateExecutionStatus(executionId, ProcessStatus.FAILED, null, null, Instant.now());
+ processExecutionContexts.remove(executionId);
+ }
} else {
processExecutionContexts.remove(executionId);
}Also applies to: 130-133 🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+85
to
+101
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Guard against duplicate run messages to avoid double modifications. Message delivery is typically at-least-once; this code generates new step IDs and calls 🛡️ Proposed deduplication guard- processExecutionContexts.put(executionId, new ProcessExecutionContext(
- applyModificationsStepId,
- securityAnalysisStepId,
- caseUuid,
- contingencies,
- parametersUuid
- ));
+ ProcessExecutionContext newContext = new ProcessExecutionContext(
+ applyModificationsStepId,
+ securityAnalysisStepId,
+ caseUuid,
+ contingencies,
+ parametersUuid
+ );
+ ProcessExecutionContext existing = processExecutionContexts.putIfAbsent(executionId, newContext);
+ if (existing != null) {
+ LOGGER.warn("Duplicate run message ignored for executionId: {}", executionId);
+ return;
+ }📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| @Bean | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| public Consumer<Message<CaseResultInfos>> consumeNetworkModifications() { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // consume message received from network-modification-server | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return message -> { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| CaseResultInfos caseResultInfos = message.getPayload(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| UUID caseResultUuid = caseResultInfos.getCaseResultUuid(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| UUID executionId = caseResultInfos.getExecutionUuid(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| String stepType = caseResultInfos.getStepType(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| UUID reportUuid = caseResultInfos.getReportUuid(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| StepStatus stepStatus = StepStatus.valueOf(caseResultInfos.getStatus()); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ProcessExecutionContext processExecutionContext = processExecutionContexts.get(executionId); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (processExecutionContext == null) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| LOGGER.error("Process execution context not found for executionId: {}", executionId); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| monitorService.updateStepStatus(executionId, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| new ProcessExecutionStep(processExecutionContext.applyModificationsStepId(), stepType, 0, stepStatus, null, null, reportUuid, null, Instant.now(), caseResultUuid)); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| monitorService.updateStepStatus(executionId, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| new ProcessExecutionStep(processExecutionContext.securityAnalysisStepId(), "SECURITY_ANALYSIS", 1, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| stepStatus == StepStatus.COMPLETED ? StepStatus.RUNNING : StepStatus.SKIPPED, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| null, null, null, Instant.now(), null, null)); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (stepStatus == StepStatus.COMPLETED) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // call security-analysis-server to run security analysis | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| securityAnalysisRestService.runSecurityAnalysis(caseResultUuid, executionId, processExecutionContext.contingencies(), processExecutionContext.parametersUuid()); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } else { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| processExecutionContexts.remove(executionId); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+130
to
+135
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Update execution status when network modifications fail. On non- 🧭 Propagate failure to the execution status if (stepStatus == StepStatus.COMPLETED) {
// call security-analysis-server to run security analysis
securityAnalysisRestService.runSecurityAnalysis(caseResultUuid, executionId, processExecutionContext.contingencies(), processExecutionContext.parametersUuid());
} else {
+ monitorService.updateExecutionStatus(executionId, ProcessStatus.FAILED, null, null, Instant.now());
processExecutionContexts.remove(executionId);
}🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| @Bean | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| public Consumer<Message<CaseResultInfos>> consumeSecurityAnalysis() { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // consume message received from security-analysis-server | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return message -> { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| CaseResultInfos caseResultInfos = message.getPayload(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| UUID executionId = caseResultInfos.getExecutionUuid(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| String stepType = caseResultInfos.getStepType(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| UUID reportUuid = caseResultInfos.getReportUuid(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| UUID resultUuid = caseResultInfos.getResultUuid(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| StepStatus stepStatus = StepStatus.valueOf(caseResultInfos.getStatus()); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| UUID caseResultUuid = caseResultInfos.getCaseResultUuid(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+149
to
+151
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: # First, locate the file and examine the current state around lines 148-149
find . -type f -name "ConsumerServiceUsingServers.java" -exec wc -l {} \;Repository: gridsuite/monitor-core Length of output: 171 🏁 Script executed: # Check the file structure and content around the specified lines
find . -type f -name "ConsumerServiceUsingServers.java" -exec sed -n '140,160p' {} +Repository: gridsuite/monitor-core Length of output: 1332 🏁 Script executed: # Find CaseResultInfos class definition
fd 'CaseResultInfos.java' -x cat -n {}Repository: gridsuite/monitor-core Length of output: 1386 🏁 Script executed: # Search for all StepStatus.valueOf usages in the codebase
rg -n "StepStatus\.valueOf" -g '*.java' -B2 -A2Repository: gridsuite/monitor-core Length of output: 1740 🏁 Script executed: # Find consumeNetworkModifications method
rg -n "consumeNetworkModifications" -g '*.java' -B2 -A10Repository: gridsuite/monitor-core Length of output: 2030 🏁 Script executed: # Check StepStatus enum definition to see valid values
fd 'StepStatus.java' -x cat -n {}Repository: gridsuite/monitor-core Length of output: 663 🏁 Script executed: # Check the method name for line 148
sed -n '130,150p' ./monitor-server/src/main/java/org/gridsuite/monitor/server/services/ConsumerServiceUsingServers.javaRepository: gridsuite/monitor-core Length of output: 1133 🏁 Script executed: # Search for any other StepStatus usages or related parsing
rg -n "StepStatus|getStatus" ./monitor-server/src/main/java/org/gridsuite/monitor/server/services/ConsumerServiceUsingServers.java -B1 -A1Repository: gridsuite/monitor-core Length of output: 2294 🏁 Script executed: # Check if there's any validation or documentation about status values from external servers
rg -n "status|Status" ./monitor-server/src/main/java/org/gridsuite/monitor/commons/CaseResultInfos.java -B2 -A2Repository: gridsuite/monitor-core Length of output: 187 Harden status parsing from external servers in two locations.
Use safe parsing with error handling and fallback in both methods. 🛡️ Safer status parsing pattern- StepStatus stepStatus = StepStatus.valueOf(caseResultInfos.getStatus());
+ StepStatus stepStatus;
+ try {
+ stepStatus = StepStatus.valueOf(caseResultInfos.getStatus());
+ } catch (IllegalArgumentException ex) {
+ LOGGER.error("Unsupported step status '{}' for executionId: {}", caseResultInfos.getStatus(), executionId, ex);
+ monitorService.updateExecutionStatus(executionId, ProcessStatus.FAILED, null, null, Instant.now());
+ processExecutionContexts.remove(executionId);
+ return;
+ }📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ProcessExecutionContext processExecutionContext = processExecutionContexts.get(executionId); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (processExecutionContext == null) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| LOGGER.error("Process execution context not found for executionId: {}", executionId); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| monitorService.updateStepStatus(executionId, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| new ProcessExecutionStep(processExecutionContext.securityAnalysisStepId(), stepType, 1, stepStatus, resultUuid, ResultType.SECURITY_ANALYSIS, reportUuid, null, Instant.now(), caseResultUuid)); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| monitorService.updateExecutionStatus(executionId, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| stepStatus == StepStatus.COMPLETED ? ProcessStatus.COMPLETED : ProcessStatus.FAILED, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| null, null, Instant.now()); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| processExecutionContexts.remove(executionId); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,54 @@ | ||
| /** | ||
| * 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.server.services; | ||
|
|
||
| import org.springframework.beans.factory.annotation.Value; | ||
| import org.springframework.boot.web.client.RestTemplateBuilder; | ||
| import org.springframework.http.HttpEntity; | ||
| import org.springframework.http.HttpHeaders; | ||
| import org.springframework.http.HttpMethod; | ||
| import org.springframework.http.MediaType; | ||
| import org.springframework.stereotype.Service; | ||
| import org.springframework.web.client.RestTemplate; | ||
| import org.springframework.web.util.UriComponentsBuilder; | ||
|
|
||
| import java.util.List; | ||
| import java.util.UUID; | ||
|
|
||
| /** | ||
| * @author Franck Lecuyer <franck.lecuyer at rte-france.com> | ||
| */ | ||
| @Service | ||
| public class NetworkModificationRestService { | ||
| private static final String NETWORK_MODIFICATION_SERVER_API_VERSION = "v1"; | ||
| private static final String DELIMITER = "/"; | ||
|
|
||
| private final RestTemplate networkModificationServerRest; | ||
| private final String networkModificationServerBaseUri; | ||
|
|
||
| public NetworkModificationRestService(@Value("${gridsuite.services.network-modification-server.base-uri:http://network-modification-server/}") String networkModificationServerBaseUri, | ||
| RestTemplateBuilder restTemplateBuilder) { | ||
| this.networkModificationServerRest = restTemplateBuilder.build(); | ||
| this.networkModificationServerBaseUri = networkModificationServerBaseUri; | ||
| } | ||
|
|
||
| public void applyModifications(UUID caseUuid, UUID executionId, List<UUID> modificationUuids) { | ||
| var uriComponentsBuilder = UriComponentsBuilder.fromPath(DELIMITER + NETWORK_MODIFICATION_SERVER_API_VERSION + DELIMITER + "cases/{caseUuid}/network-composite-modifications"); | ||
| var path = uriComponentsBuilder | ||
| .queryParam("executionUuid", executionId) | ||
| .queryParam("uuids", modificationUuids) | ||
| .buildAndExpand(caseUuid) | ||
| .toUriString(); | ||
|
|
||
| HttpHeaders headers = new HttpHeaders(); | ||
| headers.setContentType(MediaType.APPLICATION_JSON); | ||
| HttpEntity httpEntity = new HttpEntity<>(null, headers); | ||
|
Check warning on line 50 in monitor-server/src/main/java/org/gridsuite/monitor/server/services/NetworkModificationRestService.java
|
||
|
|
||
| networkModificationServerRest.exchange(networkModificationServerBaseUri + path, HttpMethod.POST, httpEntity, Void.class); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -27,6 +27,10 @@ public void sendProcessRunMessage(UUID caseUuid, ProcessConfig processConfig, UU | |
| String bindingName = switch (processConfig.processType()) { | ||
| case SECURITY_ANALYSIS -> "publishRunSecurityAnalysis-out-0"; | ||
| }; | ||
| sendProcessRunMessage(caseUuid, processConfig, executionId, bindingName, debugFileLocation); | ||
| } | ||
|
|
||
| public void sendProcessRunMessage(UUID caseUuid, ProcessConfig processConfig, UUID executionId, String bindingName, String debugFileLocation) { | ||
| ProcessRunMessage<?> message = new ProcessRunMessage<>(executionId, caseUuid, processConfig, debugFileLocation); | ||
| publisher.send(bindingName, message); | ||
| } | ||
|
Comment on lines
+33
to
36
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
# Find all call sites of the 5-arg sendProcessRunMessage overload
rg -n --type java 'sendProcessRunMessage\s*\(\s*[^,]+\s*,\s*[^,]+\s*,\s*[^,]+\s*,\s*[^,]+\s*,\s*[^,]+\s*\)' -A 2 -B 2Repository: gridsuite/monitor-core Length of output: 2037 🏁 Script executed: #!/bin/bash
# Get directory structure to understand package layout
git ls-files "monitor-server/src/main/java/org/gridsuite/monitor/server/**" | grep -E "(NotificationService|MonitorService)" | head -20Repository: gridsuite/monitor-core Length of output: 244 🏁 Script executed: #!/bin/bash
# Read the full NotificationService.java to understand the context
wc -l monitor-server/src/main/java/org/gridsuite/monitor/server/services/NotificationService.javaRepository: gridsuite/monitor-core Length of output: 160 🏁 Script executed: #!/bin/bash
# Read NotificationService.java around the method definition
cat -n monitor-server/src/main/java/org/gridsuite/monitor/server/services/NotificationService.java | head -37Repository: gridsuite/monitor-core Length of output: 1817 🏁 Script executed: #!/bin/bash
# Read MonitorService.java around the call site to see full context
sed -n '255,270p' monitor-server/src/main/java/org/gridsuite/monitor/server/services/MonitorService.java | cat -nRepository: gridsuite/monitor-core Length of output: 680 🏁 Script executed: #!/bin/bash
# Check if there are other call sites to this method
rg 'sendProcessRunMessage' monitor-server/src/main/java/org/gridsuite/monitor/server/services/ -B 1 -A 1Repository: gridsuite/monitor-core Length of output: 2266 Fix parameter order mismatch in MonitorService call to the 5-parameter overload. The call at notificationService.sendProcessRunMessage(caseUuid, processConfig, execution.getId(), null, bindingName);But the method signature expects: public void sendProcessRunMessage(..., String bindingName, String debugFileLocation)This swaps the parameters: Fix parameter order-notificationService.sendProcessRunMessage(caseUuid, processConfig, execution.getId(), null, bindingName);
+notificationService.sendProcessRunMessage(caseUuid, processConfig, execution.getId(), bindingName, null);Alternatively, to avoid this fragility in the future, consider whether this call should use the 4-parameter overload instead and let the routing logic remain centralized in 🤖 Prompt for AI Agents |
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fail fast for unsupported process types.
Only
SECURITY_ANALYSISis handled; other types leavecontingencies/parametersUuidnull but still schedule security analysis and call the SA server. Add a default branch that marks the execution failed and returns.✅ Add an explicit default branch
List<String> contingencies = null; UUID parametersUuid = null; switch (processConfig.processType()) { case SECURITY_ANALYSIS -> { - contingencies = ((SecurityAnalysisConfig) processConfig).contingencies(); - parametersUuid = ((SecurityAnalysisConfig) processConfig).parametersUuid(); + SecurityAnalysisConfig saConfig = (SecurityAnalysisConfig) processConfig; + contingencies = saConfig.contingencies(); + parametersUuid = saConfig.parametersUuid(); } + default -> { + LOGGER.error("Unsupported process type {} for executionId: {}", processConfig.processType(), executionId); + monitorService.updateExecutionStatus(executionId, ProcessStatus.FAILED, null, null, Instant.now()); + return; + } }📝 Committable suggestion
🤖 Prompt for AI Agents