diff --git a/src/main/java/org/gridsuite/study/server/dto/DeleteNodeInfos.java b/src/main/java/org/gridsuite/study/server/dto/DeleteNodeInfos.java index 3546430e5..616c5b494 100644 --- a/src/main/java/org/gridsuite/study/server/dto/DeleteNodeInfos.java +++ b/src/main/java/org/gridsuite/study/server/dto/DeleteNodeInfos.java @@ -20,6 +20,8 @@ @Getter @Setter public class DeleteNodeInfos { + private List removedNodeUuids = new ArrayList<>(); + private List modificationGroupUuids = new ArrayList<>(); private List reportUuids = new ArrayList<>(); @@ -46,6 +48,10 @@ public class DeleteNodeInfos { private List stateEstimationResultUuids = new ArrayList<>(); + public void addRemovedNodeUuid(UUID removedNodeUuid) { + removedNodeUuids.add(removedNodeUuid); + } + public void addModificationGroupUuid(UUID modificationGroupUuid) { modificationGroupUuids.add(modificationGroupUuid); } diff --git a/src/main/java/org/gridsuite/study/server/service/LoadFlowService.java b/src/main/java/org/gridsuite/study/server/service/LoadFlowService.java index 28482853b..1e165ffd7 100644 --- a/src/main/java/org/gridsuite/study/server/service/LoadFlowService.java +++ b/src/main/java/org/gridsuite/study/server/service/LoadFlowService.java @@ -106,10 +106,6 @@ public void deleteLoadFlowResults(List resultsUuids) { deleteCalculationResults(resultsUuids, DELIMITER + LOADFLOW_API_VERSION + "/results", restTemplate, loadFlowServerBaseUri); } - public void deleteAllLoadFlowResults() { - deleteLoadFlowResults(null); - } - public Integer getLoadFlowResultsCount() { String path = UriComponentsBuilder .fromPath(DELIMITER + LOADFLOW_API_VERSION + "/supervision/results-count").toUriString(); diff --git a/src/main/java/org/gridsuite/study/server/service/NetworkModificationTreeService.java b/src/main/java/org/gridsuite/study/server/service/NetworkModificationTreeService.java index 1adc0216a..da7793993 100644 --- a/src/main/java/org/gridsuite/study/server/service/NetworkModificationTreeService.java +++ b/src/main/java/org/gridsuite/study/server/service/NetworkModificationTreeService.java @@ -271,12 +271,10 @@ public void moveStudySubtree(UUID parentNodeToMoveUuid, UUID anchorNodeUuid) { @Transactional // TODO test if studyUuid exist and have a node - public List doDeleteNode(UUID nodeId, boolean deleteChildren, DeleteNodeInfos deleteNodeInfos) { - List removedNodes = new ArrayList<>(); + public void doDeleteNode(UUID nodeId, boolean deleteChildren, DeleteNodeInfos deleteNodeInfos) { UUID studyId = self.getStudyUuidForNodeId(nodeId); - deleteNodes(nodeId, deleteChildren, false, removedNodes, deleteNodeInfos); - notificationService.emitNodesDeleted(studyId, removedNodes, deleteChildren); - return removedNodes; + deleteNodes(nodeId, deleteChildren, false, deleteNodeInfos); + notificationService.emitNodesDeleted(studyId, deleteNodeInfos.getRemovedNodeUuids(), deleteChildren); } @Transactional @@ -314,7 +312,7 @@ private void stashNodes(UUID id, boolean stashChildren, List stashedNodes, }); } - private void deleteNodes(UUID id, boolean deleteChildren, boolean allowDeleteRoot, List removedNodes, DeleteNodeInfos deleteNodeInfos) { + private void deleteNodes(UUID id, boolean deleteChildren, boolean allowDeleteRoot, DeleteNodeInfos deleteNodeInfos) { Optional optNodeToDelete = nodesRepository.findById(id); optNodeToDelete.ifPresent(nodeToDelete -> { /* root cannot be deleted by accident */ @@ -332,9 +330,9 @@ private void deleteNodes(UUID id, boolean deleteChildren, boolean allowDeleteRoo getChildren(id).forEach(node -> node.setParentNode(nodeToDelete.getParentNode())); } else { getChildren(id) - .forEach(child -> deleteNodes(child.getIdNode(), true, false, removedNodes, deleteNodeInfos)); + .forEach(child -> deleteNodes(child.getIdNode(), true, false, deleteNodeInfos)); } - removedNodes.add(id); + deleteNodeInfos.addRemovedNodeUuid(id); if (nodeToDelete.getType() == NodeType.ROOT) { rootNodeInfoRepository.deleteById(id); } else { diff --git a/src/main/java/org/gridsuite/study/server/service/RootNetworkNodeInfoService.java b/src/main/java/org/gridsuite/study/server/service/RootNetworkNodeInfoService.java index 2c01b50c5..d58b4c032 100644 --- a/src/main/java/org/gridsuite/study/server/service/RootNetworkNodeInfoService.java +++ b/src/main/java/org/gridsuite/study/server/service/RootNetworkNodeInfoService.java @@ -492,20 +492,20 @@ public void updateRootNetworkNode(UUID nodeUuid, UUID rootNetworkUuid, RootNetwo } } - public Stream> getDeleteRootNetworkNodeInfosFutures(List rootNetworkNodeInfo) { - return Stream.of( - studyServerExecutionService.runAsync(() -> reportService.deleteReports(rootNetworkNodeInfo.stream().map(this::getReportUuids).flatMap(Collection::stream).toList())), - studyServerExecutionService.runAsync(() -> loadFlowService.deleteLoadFlowResults(rootNetworkNodeInfo.stream().map(RootNetworkNodeInfo::getLoadFlowResultUuid).filter(Objects::nonNull).toList())), - studyServerExecutionService.runAsync(() -> securityAnalysisService.deleteSecurityAnalysisResults(rootNetworkNodeInfo.stream() + public void deleteRootNetworkNodeRemoteInfos(List rootNetworkNodeInfo) { + CompletableFuture.allOf( + studyServerExecutionService.runAsyncAndComplete(() -> reportService.deleteReports(rootNetworkNodeInfo.stream().map(this::getReportUuids).flatMap(Collection::stream).toList())), + studyServerExecutionService.runAsyncAndComplete(() -> loadFlowService.deleteLoadFlowResults(rootNetworkNodeInfo.stream().map(RootNetworkNodeInfo::getLoadFlowResultUuid).filter(Objects::nonNull).toList())), + studyServerExecutionService.runAsyncAndComplete(() -> securityAnalysisService.deleteSecurityAnalysisResults(rootNetworkNodeInfo.stream() .map(RootNetworkNodeInfo::getSecurityAnalysisResultUuid).filter(Objects::nonNull).toList())), - studyServerExecutionService.runAsync(() -> sensitivityAnalysisService.deleteSensitivityAnalysisResults(rootNetworkNodeInfo.stream().map(RootNetworkNodeInfo::getSensitivityAnalysisResultUuid).filter(Objects::nonNull).toList())), - studyServerExecutionService.runAsync(() -> nonEvacuatedEnergyService.deleteNonEvacuatedEnergyResults(rootNetworkNodeInfo.stream().map(RootNetworkNodeInfo::getNonEvacuatedEnergyResultUuid).filter(Objects::nonNull).toList())), - studyServerExecutionService.runAsync(() -> shortCircuitService.deleteShortCircuitAnalysisResults(rootNetworkNodeInfo.stream().map(RootNetworkNodeInfo::getShortCircuitAnalysisResultUuid).filter(Objects::nonNull).toList())), - studyServerExecutionService.runAsync(() -> shortCircuitService.deleteShortCircuitAnalysisResults(rootNetworkNodeInfo.stream().map(RootNetworkNodeInfo::getOneBusShortCircuitAnalysisResultUuid).filter(Objects::nonNull).toList())), - studyServerExecutionService.runAsync(() -> voltageInitService.deleteVoltageInitResults(rootNetworkNodeInfo.stream().map(RootNetworkNodeInfo::getVoltageInitResultUuid).filter(Objects::nonNull).toList())), - studyServerExecutionService.runAsync(() -> dynamicSimulationService.deleteResults(rootNetworkNodeInfo.stream().map(RootNetworkNodeInfo::getDynamicSimulationResultUuid).filter(Objects::nonNull).toList())), - studyServerExecutionService.runAsync(() -> dynamicSecurityAnalysisService.deleteResults(rootNetworkNodeInfo.stream().map(RootNetworkNodeInfo::getDynamicSecurityAnalysisResultUuid).filter(Objects::nonNull).toList())), - studyServerExecutionService.runAsync(() -> stateEstimationService.deleteStateEstimationResults(rootNetworkNodeInfo.stream().map(RootNetworkNodeInfo::getStateEstimationResultUuid).filter(Objects::nonNull).toList())) + studyServerExecutionService.runAsyncAndComplete(() -> sensitivityAnalysisService.deleteSensitivityAnalysisResults(rootNetworkNodeInfo.stream().map(RootNetworkNodeInfo::getSensitivityAnalysisResultUuid).filter(Objects::nonNull).toList())), + studyServerExecutionService.runAsyncAndComplete(() -> nonEvacuatedEnergyService.deleteNonEvacuatedEnergyResults(rootNetworkNodeInfo.stream().map(RootNetworkNodeInfo::getNonEvacuatedEnergyResultUuid).filter(Objects::nonNull).toList())), + studyServerExecutionService.runAsyncAndComplete(() -> shortCircuitService.deleteShortCircuitAnalysisResults(rootNetworkNodeInfo.stream().map(RootNetworkNodeInfo::getShortCircuitAnalysisResultUuid).filter(Objects::nonNull).toList())), + studyServerExecutionService.runAsyncAndComplete(() -> shortCircuitService.deleteShortCircuitAnalysisResults(rootNetworkNodeInfo.stream().map(RootNetworkNodeInfo::getOneBusShortCircuitAnalysisResultUuid).filter(Objects::nonNull).toList())), + studyServerExecutionService.runAsyncAndComplete(() -> voltageInitService.deleteVoltageInitResults(rootNetworkNodeInfo.stream().map(RootNetworkNodeInfo::getVoltageInitResultUuid).filter(Objects::nonNull).toList())), + studyServerExecutionService.runAsyncAndComplete(() -> dynamicSimulationService.deleteResults(rootNetworkNodeInfo.stream().map(RootNetworkNodeInfo::getDynamicSimulationResultUuid).filter(Objects::nonNull).toList())), + studyServerExecutionService.runAsyncAndComplete(() -> dynamicSecurityAnalysisService.deleteResults(rootNetworkNodeInfo.stream().map(RootNetworkNodeInfo::getDynamicSecurityAnalysisResultUuid).filter(Objects::nonNull).toList())), + studyServerExecutionService.runAsyncAndComplete(() -> stateEstimationService.deleteStateEstimationResults(rootNetworkNodeInfo.stream().map(RootNetworkNodeInfo::getStateEstimationResultUuid).filter(Objects::nonNull).toList())) ); } diff --git a/src/main/java/org/gridsuite/study/server/service/RootNetworkService.java b/src/main/java/org/gridsuite/study/server/service/RootNetworkService.java index 3a8be7b06..5a88a78fa 100644 --- a/src/main/java/org/gridsuite/study/server/service/RootNetworkService.java +++ b/src/main/java/org/gridsuite/study/server/service/RootNetworkService.java @@ -235,35 +235,22 @@ public void deleteRootNetworks(StudyEntity studyEntity, Stream rootNetwork } public void deleteRootNetworks(StudyEntity studyEntity, List rootNetworksInfos) { - CompletableFuture executeInParallel = CompletableFuture.allOf( - getDeleteRootNetworkInfosFutures(rootNetworksInfos).toArray(CompletableFuture[]::new) - ); - - try { - executeInParallel.get(); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - throw new StudyException(DELETE_ROOT_NETWORK_FAILED, e.getMessage()); - } catch (Exception e) { - throw new StudyException(DELETE_ROOT_NETWORK_FAILED, e.getMessage()); - } + deleteRootNetworkRemoteInfos(rootNetworksInfos); studyEntity.deleteRootNetworks(rootNetworksInfos.stream().map(RootNetworkInfos::getId).collect(Collectors.toSet())); } - public Stream> getDeleteRootNetworkInfosFutures(List rootNetworkInfos) { - return Stream - .concat( - // delete remote data ids set in root network - Stream.of( - studyServerExecutionService.runAsync(() -> reportService.deleteReports(rootNetworkInfos.stream().map(RootNetworkInfos::getReportUuid).toList())), - studyServerExecutionService.runAsync(() -> rootNetworkInfos.stream().map(rni -> rni.getNetworkInfos().getNetworkUuid()).filter(Objects::nonNull).forEach(equipmentInfosService::deleteEquipmentIndexes)), - studyServerExecutionService.runAsync(() -> rootNetworkInfos.stream().map(rni -> rni.getNetworkInfos().getNetworkUuid()).filter(Objects::nonNull).forEach(networkStoreService::deleteNetwork)), - studyServerExecutionService.runAsync(() -> rootNetworkInfos.stream().map(rni -> rni.getCaseInfos().getCaseUuid()).filter(Objects::nonNull).forEach(caseService::deleteCase)) - ), - // delete remote data ids set in root network node infos - rootNetworkNodeInfoService.getDeleteRootNetworkNodeInfosFutures(rootNetworkInfos.stream().map(RootNetworkInfos::getRootNetworkNodeInfos).filter(Objects::nonNull).flatMap(Collection::stream).toList()) - ); + public void deleteRootNetworkRemoteInfos(List rootNetworkInfos) { + CompletableFuture.allOf( + // delete remote data ids set in root network + studyServerExecutionService.runAsyncAndComplete(() -> reportService.deleteReports(rootNetworkInfos.stream().map(RootNetworkInfos::getReportUuid).toList())), + studyServerExecutionService.runAsyncAndComplete(() -> rootNetworkInfos.stream().map(rni -> rni.getNetworkInfos().getNetworkUuid()).filter(Objects::nonNull).forEach(equipmentInfosService::deleteEquipmentIndexes)), + studyServerExecutionService.runAsyncAndComplete(() -> rootNetworkInfos.stream().map(rni -> rni.getNetworkInfos().getNetworkUuid()).filter(Objects::nonNull).forEach(networkStoreService::deleteNetwork)), + studyServerExecutionService.runAsyncAndComplete(() -> rootNetworkInfos.stream().map(rni -> rni.getCaseInfos().getCaseUuid()).filter(Objects::nonNull).forEach(caseService::deleteCase)) + ); + + // delete remote data ids set in root network node infos + rootNetworkNodeInfoService.deleteRootNetworkNodeRemoteInfos(rootNetworkInfos.stream().map(RootNetworkInfos::getRootNetworkNodeInfos).filter(Objects::nonNull).flatMap(Collection::stream).toList()); } public Optional getRootNetworkRequest(UUID rootNetworkUuid) { diff --git a/src/main/java/org/gridsuite/study/server/service/StudyServerExecutionService.java b/src/main/java/org/gridsuite/study/server/service/StudyServerExecutionService.java index 8af29c788..1f146c957 100644 --- a/src/main/java/org/gridsuite/study/server/service/StudyServerExecutionService.java +++ b/src/main/java/org/gridsuite/study/server/service/StudyServerExecutionService.java @@ -9,6 +9,8 @@ import jakarta.annotation.PostConstruct; import jakarta.annotation.PreDestroy; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.stereotype.Service; import java.util.concurrent.CompletableFuture; @@ -18,6 +20,8 @@ @Service public class StudyServerExecutionService { + private static final Logger LOGGER = LoggerFactory.getLogger(StudyServerExecutionService.class); + private ExecutorService executorService; @PostConstruct @@ -33,4 +37,14 @@ private void preDestroy() { public CompletableFuture runAsync(Runnable runnable) { return CompletableFuture.runAsync(runnable, executorService); } + + public CompletableFuture runAsyncAndComplete(Runnable runnable) { + return CompletableFuture.runAsync(runnable, executorService).whenCompleteAsync((r, t) -> logAsyncError(t)); + } + + private void logAsyncError(Throwable e) { + if (LOGGER.isErrorEnabled() && e != null) { + LOGGER.error(e.toString(), e); + } + } } diff --git a/src/main/java/org/gridsuite/study/server/service/StudyService.java b/src/main/java/org/gridsuite/study/server/service/StudyService.java index c5b89334c..2291f1ceb 100644 --- a/src/main/java/org/gridsuite/study/server/service/StudyService.java +++ b/src/main/java/org/gridsuite/study/server/service/StudyService.java @@ -579,39 +579,19 @@ private void removeNetworkVisualizationParameters(@Nullable UUID uuid) { @Transactional public void deleteStudyIfNotCreationInProgress(UUID studyUuid) { AtomicReference startTime = new AtomicReference<>(null); - try { - Optional deleteStudyInfosOpt = doDeleteStudyIfNotCreationInProgress(studyUuid); - if (deleteStudyInfosOpt.isPresent()) { - DeleteStudyInfos deleteStudyInfos = deleteStudyInfosOpt.get(); - startTime.set(System.nanoTime()); - - //TODO: now we have a n-n relation between node and rootNetworks, it's even more important to delete results in a single request - CompletableFuture executeInParallel = CompletableFuture.allOf( - Stream.concat( - // delete all distant resources linked to rootNetworks - rootNetworkService.getDeleteRootNetworkInfosFutures(deleteStudyInfos.getRootNetworkInfosList()), - // delete all distant resources linked to nodes - Stream.of( - studyServerExecutionService.runAsync( - () -> deleteStudyInfos.getModificationGroupUuids() - .stream() - .filter(Objects::nonNull) - .forEach(networkModificationService::deleteModifications) - ) - ) // TODO delete all with one request only - ).toArray(CompletableFuture[]::new) - ); - - executeInParallel.get(); - if (startTime.get() != null) { - LOGGER.trace("Delete study '{}' : {} seconds", studyUuid, TimeUnit.NANOSECONDS.toSeconds(System.nanoTime() - startTime.get())); - } - } - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - throw new StudyException(DELETE_STUDY_FAILED, e.getMessage()); - } catch (Exception e) { - throw new StudyException(DELETE_STUDY_FAILED, e.getMessage()); + Optional deleteStudyInfosOpt = doDeleteStudyIfNotCreationInProgress(studyUuid); + if (deleteStudyInfosOpt.isPresent()) { + DeleteStudyInfos deleteStudyInfos = deleteStudyInfosOpt.get(); + startTime.set(System.nanoTime()); + + // delete all distant resources linked to rootNetworks + rootNetworkService.deleteRootNetworkRemoteInfos(deleteStudyInfos.getRootNetworkInfosList()); + + // delete all distant resources linked to nodes + studyServerExecutionService.runAsyncAndComplete(() -> deleteStudyInfos.getModificationGroupUuids().stream().filter(Objects::nonNull).forEach(networkModificationService::deleteModifications)); + + LOGGER.trace("Delete study '{}' : {} seconds", studyUuid, TimeUnit.NANOSECONDS.toSeconds(System.nanoTime() - startTime.get())); + } } @@ -2109,33 +2089,6 @@ public void unblockNodeTree(UUID studyUuid, UUID nodeUuid) { ); } - private void deleteInvalidationInfos(InvalidateNodeInfos invalidateNodeInfos) { - CompletableFuture executeInParallel = CompletableFuture.allOf( - studyServerExecutionService.runAsync(() -> networkModificationService.deleteIndexedModifications(invalidateNodeInfos.getGroupUuids(), invalidateNodeInfos.getNetworkUuid())), - studyServerExecutionService.runAsync(() -> networkStoreService.deleteVariants(invalidateNodeInfos.getNetworkUuid(), invalidateNodeInfos.getVariantIds())), - studyServerExecutionService.runAsync(() -> reportService.deleteReports(invalidateNodeInfos.getReportUuids())), - studyServerExecutionService.runAsync(() -> loadflowService.deleteLoadFlowResults(invalidateNodeInfos.getLoadFlowResultUuids())), - studyServerExecutionService.runAsync(() -> securityAnalysisService.deleteSecurityAnalysisResults(invalidateNodeInfos.getSecurityAnalysisResultUuids())), - studyServerExecutionService.runAsync(() -> sensitivityAnalysisService.deleteSensitivityAnalysisResults(invalidateNodeInfos.getSensitivityAnalysisResultUuids())), - studyServerExecutionService.runAsync(() -> nonEvacuatedEnergyService.deleteNonEvacuatedEnergyResults(invalidateNodeInfos.getNonEvacuatedEnergyResultUuids())), - studyServerExecutionService.runAsync(() -> shortCircuitService.deleteShortCircuitAnalysisResults(invalidateNodeInfos.getShortCircuitAnalysisResultUuids())), - studyServerExecutionService.runAsync(() -> shortCircuitService.deleteShortCircuitAnalysisResults(invalidateNodeInfos.getOneBusShortCircuitAnalysisResultUuids())), - studyServerExecutionService.runAsync(() -> voltageInitService.deleteVoltageInitResults(invalidateNodeInfos.getVoltageInitResultUuids())), - studyServerExecutionService.runAsync(() -> dynamicSimulationService.deleteResults(invalidateNodeInfos.getDynamicSimulationResultUuids())), - studyServerExecutionService.runAsync(() -> dynamicSecurityAnalysisService.deleteResults(invalidateNodeInfos.getDynamicSecurityAnalysisResultUuids())), - studyServerExecutionService.runAsync(() -> stateEstimationService.deleteStateEstimationResults(invalidateNodeInfos.getStateEstimationResultUuids())) - ); - try { - executeInParallel.get(); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - throw new StudyException(INVALIDATE_BUILD_FAILED, e.getMessage()); - } catch (Exception e) { - throw new StudyException(INVALIDATE_BUILD_FAILED, e.getMessage()); - } - - } - @Transactional public void deleteNetworkModifications(UUID studyUuid, UUID nodeUuid, List modificationsUuids, String userId) { List childrenUuids = networkModificationTreeService.getChildrenUuids(nodeUuid); @@ -2249,47 +2202,62 @@ public void deleteNodes(UUID studyUuid, List nodeIds, boolean deleteChildr boolean invalidateChildrenBuild = !deleteChildren && networkModificationTreeService.hasModifications(nodeId, false); List childrenNodes = networkModificationTreeService.getChildren(nodeId); - List removedNodes = networkModificationTreeService.doDeleteNode(nodeId, deleteChildren, deleteNodeInfos); - - CompletableFuture executeInParallel = CompletableFuture.allOf( - studyServerExecutionService.runAsync(() -> deleteNodeInfos.getModificationGroupUuids().forEach(networkModificationService::deleteModifications)), - studyServerExecutionService.runAsync(() -> reportService.deleteReports(deleteNodeInfos.getReportUuids())), - studyServerExecutionService.runAsync(() -> loadflowService.deleteLoadFlowResults(deleteNodeInfos.getLoadFlowResultUuids())), - studyServerExecutionService.runAsync(() -> securityAnalysisService.deleteSecurityAnalysisResults(deleteNodeInfos.getSecurityAnalysisResultUuids())), - studyServerExecutionService.runAsync(() -> sensitivityAnalysisService.deleteSensitivityAnalysisResults(deleteNodeInfos.getSensitivityAnalysisResultUuids())), - studyServerExecutionService.runAsync(() -> nonEvacuatedEnergyService.deleteNonEvacuatedEnergyResults(deleteNodeInfos.getNonEvacuatedEnergyResultUuids())), - studyServerExecutionService.runAsync(() -> shortCircuitService.deleteShortCircuitAnalysisResults(deleteNodeInfos.getShortCircuitAnalysisResultUuids())), - studyServerExecutionService.runAsync(() -> shortCircuitService.deleteShortCircuitAnalysisResults(deleteNodeInfos.getOneBusShortCircuitAnalysisResultUuids())), - studyServerExecutionService.runAsync(() -> voltageInitService.deleteVoltageInitResults(deleteNodeInfos.getVoltageInitResultUuids())), - studyServerExecutionService.runAsync(() -> dynamicSimulationService.deleteResults(deleteNodeInfos.getDynamicSimulationResultUuids())), - studyServerExecutionService.runAsync(() -> dynamicSecurityAnalysisService.deleteResults(deleteNodeInfos.getDynamicSecurityAnalysisResultUuids())), - studyServerExecutionService.runAsync(() -> stateEstimationService.deleteStateEstimationResults(deleteNodeInfos.getStateEstimationResultUuids())), - studyServerExecutionService.runAsync(() -> deleteNodeInfos.getVariantIds().forEach(networkStoreService::deleteVariants)), - studyServerExecutionService.runAsync(() -> removedNodes.forEach(dynamicSimulationEventService::deleteEventsByNodeId)) - ); + networkModificationTreeService.doDeleteNode(nodeId, deleteChildren, deleteNodeInfos); - try { - executeInParallel.get(); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - throw new StudyException(DELETE_NODE_FAILED, e.getMessage()); - } catch (Exception e) { - throw new StudyException(DELETE_NODE_FAILED, e.getMessage()); + if (invalidateChildrenBuild) { + childrenNodes.forEach(nodeEntity -> invalidateNodeTree(studyUuid, nodeEntity.getIdNode())); } if (startTime.get() != null && LOGGER.isTraceEnabled()) { LOGGER.trace("Delete node '{}' of study '{}' : {} seconds", nodeId.toString().replaceAll("[\n\r]", "_"), studyUuid, - TimeUnit.NANOSECONDS.toSeconds(System.nanoTime() - startTime.get())); - } - - if (invalidateChildrenBuild) { - childrenNodes.forEach(nodeEntity -> invalidateNodeTree(studyUuid, nodeEntity.getIdNode())); + TimeUnit.NANOSECONDS.toSeconds(System.nanoTime() - startTime.get())); } } + deleteNodesInfos(deleteNodeInfos); + notificationService.emitElementUpdated(studyUuid, userId); } + // /!\ Do not wait completion and do not throw exception + private void deleteInvalidationInfos(InvalidateNodeInfos invalidateNodeInfos) { + CompletableFuture.allOf( + studyServerExecutionService.runAsyncAndComplete(() -> networkStoreService.deleteVariants(invalidateNodeInfos.getNetworkUuid(), invalidateNodeInfos.getVariantIds())), + studyServerExecutionService.runAsyncAndComplete(() -> networkModificationService.deleteIndexedModifications(invalidateNodeInfos.getGroupUuids(), invalidateNodeInfos.getNetworkUuid())), + studyServerExecutionService.runAsyncAndComplete(() -> reportService.deleteReports(invalidateNodeInfos.getReportUuids())), + studyServerExecutionService.runAsyncAndComplete(() -> loadflowService.deleteLoadFlowResults(invalidateNodeInfos.getLoadFlowResultUuids())), + studyServerExecutionService.runAsyncAndComplete(() -> securityAnalysisService.deleteSecurityAnalysisResults(invalidateNodeInfos.getSecurityAnalysisResultUuids())), + studyServerExecutionService.runAsyncAndComplete(() -> sensitivityAnalysisService.deleteSensitivityAnalysisResults(invalidateNodeInfos.getSensitivityAnalysisResultUuids())), + studyServerExecutionService.runAsyncAndComplete(() -> nonEvacuatedEnergyService.deleteNonEvacuatedEnergyResults(invalidateNodeInfos.getNonEvacuatedEnergyResultUuids())), + studyServerExecutionService.runAsyncAndComplete(() -> shortCircuitService.deleteShortCircuitAnalysisResults(invalidateNodeInfos.getShortCircuitAnalysisResultUuids())), + studyServerExecutionService.runAsyncAndComplete(() -> shortCircuitService.deleteShortCircuitAnalysisResults(invalidateNodeInfos.getOneBusShortCircuitAnalysisResultUuids())), + studyServerExecutionService.runAsyncAndComplete(() -> voltageInitService.deleteVoltageInitResults(invalidateNodeInfos.getVoltageInitResultUuids())), + studyServerExecutionService.runAsyncAndComplete(() -> dynamicSimulationService.deleteResults(invalidateNodeInfos.getDynamicSimulationResultUuids())), + studyServerExecutionService.runAsyncAndComplete(() -> dynamicSecurityAnalysisService.deleteResults(invalidateNodeInfos.getDynamicSecurityAnalysisResultUuids())), + studyServerExecutionService.runAsyncAndComplete(() -> stateEstimationService.deleteStateEstimationResults(invalidateNodeInfos.getStateEstimationResultUuids())) + ); + } + + // /!\ Do not wait completion and do not throw exception + private void deleteNodesInfos(DeleteNodeInfos deleteNodeInfos) { + CompletableFuture.allOf( + studyServerExecutionService.runAsyncAndComplete(() -> deleteNodeInfos.getVariantIds().forEach(networkStoreService::deleteVariants)), + studyServerExecutionService.runAsyncAndComplete(() -> deleteNodeInfos.getModificationGroupUuids().forEach(networkModificationService::deleteModifications)), + studyServerExecutionService.runAsyncAndComplete(() -> deleteNodeInfos.getRemovedNodeUuids().forEach(dynamicSimulationEventService::deleteEventsByNodeId)), + studyServerExecutionService.runAsyncAndComplete(() -> reportService.deleteReports(deleteNodeInfos.getReportUuids())), + studyServerExecutionService.runAsyncAndComplete(() -> loadflowService.deleteLoadFlowResults(deleteNodeInfos.getLoadFlowResultUuids())), + studyServerExecutionService.runAsyncAndComplete(() -> securityAnalysisService.deleteSecurityAnalysisResults(deleteNodeInfos.getSecurityAnalysisResultUuids())), + studyServerExecutionService.runAsyncAndComplete(() -> sensitivityAnalysisService.deleteSensitivityAnalysisResults(deleteNodeInfos.getSensitivityAnalysisResultUuids())), + studyServerExecutionService.runAsyncAndComplete(() -> nonEvacuatedEnergyService.deleteNonEvacuatedEnergyResults(deleteNodeInfos.getNonEvacuatedEnergyResultUuids())), + studyServerExecutionService.runAsyncAndComplete(() -> shortCircuitService.deleteShortCircuitAnalysisResults(deleteNodeInfos.getShortCircuitAnalysisResultUuids())), + studyServerExecutionService.runAsyncAndComplete(() -> shortCircuitService.deleteShortCircuitAnalysisResults(deleteNodeInfos.getOneBusShortCircuitAnalysisResultUuids())), + studyServerExecutionService.runAsyncAndComplete(() -> voltageInitService.deleteVoltageInitResults(deleteNodeInfos.getVoltageInitResultUuids())), + studyServerExecutionService.runAsyncAndComplete(() -> dynamicSimulationService.deleteResults(deleteNodeInfos.getDynamicSimulationResultUuids())), + studyServerExecutionService.runAsyncAndComplete(() -> dynamicSecurityAnalysisService.deleteResults(deleteNodeInfos.getDynamicSecurityAnalysisResultUuids())), + studyServerExecutionService.runAsyncAndComplete(() -> stateEstimationService.deleteStateEstimationResults(deleteNodeInfos.getStateEstimationResultUuids())) + ); + } + @Transactional public void stashNode(UUID studyUuid, UUID nodeId, boolean stashChildren, String userId) { removeNodesFromAliases(studyUuid, List.of(nodeId), stashChildren); diff --git a/src/test/java/org/gridsuite/study/server/LoadFLowUnitTest.java b/src/test/java/org/gridsuite/study/server/LoadFLowUnitTest.java index 384b1c92b..d39e190e1 100644 --- a/src/test/java/org/gridsuite/study/server/LoadFLowUnitTest.java +++ b/src/test/java/org/gridsuite/study/server/LoadFLowUnitTest.java @@ -16,8 +16,10 @@ import org.gridsuite.study.server.repository.StudyRepository; import org.gridsuite.study.server.service.*; import org.gridsuite.study.server.utils.elasticsearch.DisableElasticsearch; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.mockito.ArgumentCaptor; +import org.mockito.stubbing.Answer; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.mock.mockito.MockBean; @@ -26,6 +28,7 @@ import java.util.List; import java.util.Optional; import java.util.UUID; +import java.util.concurrent.CompletableFuture; import static org.assertj.core.api.Assertions.assertThat; import static org.gridsuite.study.server.dto.ComputationType.LOAD_FLOW; @@ -71,6 +74,18 @@ class LoadFLowUnitTest { @MockBean StudyRepository studyRepository; + @SpyBean + private StudyServerExecutionService studyServerExecutionService; + + @BeforeEach + void setup() { + // Synchronize for tests + doAnswer((Answer) invocation -> { + CompletableFuture.runAsync((Runnable) invocation.getArguments()[0]).get(); + return CompletableFuture.completedFuture(null); + }).when(studyServerExecutionService).runAsyncAndComplete(any(Runnable.class)); + } + @Test void testRunLoadFlow() { when(rootNetworkNodeInfoService.getComputationResultUuid(nodeUuid, rootNetworkUuid, LOAD_FLOW)).thenReturn(null); diff --git a/src/test/java/org/gridsuite/study/server/NetworkModificationTest.java b/src/test/java/org/gridsuite/study/server/NetworkModificationTest.java index b5415ffec..fb33319ec 100644 --- a/src/test/java/org/gridsuite/study/server/NetworkModificationTest.java +++ b/src/test/java/org/gridsuite/study/server/NetworkModificationTest.java @@ -46,7 +46,6 @@ import org.gridsuite.study.server.service.*; import org.gridsuite.study.server.service.client.dynamicsecurityanalysis.DynamicSecurityAnalysisClient; import org.gridsuite.study.server.service.client.dynamicsimulation.DynamicSimulationClient; -import org.gridsuite.study.server.service.LoadFlowService; import org.gridsuite.study.server.service.shortcircuit.ShortCircuitService; import org.gridsuite.study.server.utils.*; import org.gridsuite.study.server.utils.elasticsearch.DisableElasticsearch; @@ -58,6 +57,7 @@ import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.EnumSource; +import org.mockito.stubbing.Answer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -76,6 +76,7 @@ import org.springframework.test.web.servlet.MvcResult; import java.util.*; +import java.util.concurrent.CompletableFuture; import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.wireMockConfig; import static org.gridsuite.study.server.StudyConstants.HEADER_ERROR_MESSAGE; @@ -86,8 +87,8 @@ import static org.gridsuite.study.server.utils.SendInput.POST_ACTION_SEND_INPUT; import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.jupiter.api.Assertions.*; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.when; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.*; import static org.springframework.http.MediaType.APPLICATION_JSON; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; @@ -234,6 +235,9 @@ class NetworkModificationTest { @Autowired private TestUtils studyTestUtils; + @SpyBean + private StudyServerExecutionService studyServerExecutionService; + @Autowired private ObjectMapper objectMapper; @@ -261,6 +265,12 @@ void setup(final MockWebServer server) { when(networkStoreService.getNetwork(NETWORK_UUID)).thenReturn(network); + // Synchronize for tests + doAnswer((Answer) invocation -> { + CompletableFuture.runAsync((Runnable) invocation.getArguments()[0]).get(); + return CompletableFuture.completedFuture(null); + }).when(studyServerExecutionService).runAsyncAndComplete(any(Runnable.class)); + wireMockServer = new WireMockServer(wireMockConfig().dynamicPort().extensions(new SendInput(input))); wireMockUtils = new WireMockUtils(wireMockServer); diff --git a/src/test/java/org/gridsuite/study/server/StudyTest.java b/src/test/java/org/gridsuite/study/server/StudyTest.java index 6fa03ffbe..72ad6666b 100644 --- a/src/test/java/org/gridsuite/study/server/StudyTest.java +++ b/src/test/java/org/gridsuite/study/server/StudyTest.java @@ -52,7 +52,6 @@ import org.gridsuite.study.server.repository.rootnetwork.RootNetworkEntity; import org.gridsuite.study.server.repository.rootnetwork.RootNetworkRepository; import org.gridsuite.study.server.service.*; -import org.gridsuite.study.server.service.LoadFlowService; import org.gridsuite.study.server.service.shortcircuit.ShortCircuitService; import org.gridsuite.study.server.utils.*; import org.gridsuite.study.server.utils.elasticsearch.DisableElasticsearch; @@ -87,7 +86,9 @@ import java.net.URLDecoder; import java.nio.charset.StandardCharsets; import java.util.*; +import java.util.concurrent.CompletableFuture; import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -361,6 +362,9 @@ class StudyTest { @Autowired private TestUtils studyTestUtils; + @SpyBean + private StudyServerExecutionService studyServerExecutionService; + private static EquipmentInfos toEquipmentInfos(Line line) { return EquipmentInfos.builder() .networkUuid(NETWORK_UUID) @@ -400,6 +404,15 @@ private void initMockBeans(Network network) { .thenReturn(List.of(new VariantInfos(VariantManagerConstants.INITIAL_VARIANT_ID, 0))); doNothing().when(networkStoreService).deleteNetwork(NETWORK_UUID); + + // Synchronize for tests + doAnswer((Answer) invocation -> { + try { + CompletableFuture.runAsync((Runnable) invocation.getArguments()[0]).get(); + } catch (ExecutionException e) { // in complete async mode we ignore exception (log only) + } + return CompletableFuture.completedFuture(null); + }).when(studyServerExecutionService).runAsyncAndComplete(any(Runnable.class)); } private void initMockBeansNetworkNotExisting() { @@ -1011,13 +1024,14 @@ void testDeleteStudyWithError(final MockWebServer server) throws Exception { studyEntity.setSpreadsheetConfigCollectionUuid(UUID.randomUUID()); studyRepository.save(studyEntity); + // We ignore error when remote data async remove doAnswer(invocation -> { throw new InterruptedException(); }).when(caseService).deleteCase(any()); UUID stubUuid = wireMockUtils.stubNetworkModificationDeleteGroup(); mockMvc.perform(delete("/v1/studies/{studyUuid}", studyUuid).header(USER_ID_HEADER, "userId")) - .andExpectAll(status().isInternalServerError(), content().string(InterruptedException.class.getName())); + .andExpectAll(status().isOk()); wireMockUtils.verifyNetworkModificationDeleteGroup(stubUuid);