Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions src/components/computing-status/use-all-computing-status.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ import { fetchDynamicSecurityAnalysisStatus } from '../../services/study/dynamic
import { fetchDynamicMarginCalculationStatus } from '../../services/study/dynamic-margin-calculation';
import { NotificationType } from 'types/notification-types';
import { fetchPccMinStatus } from 'services/study/pcc-min';
import { fetchAllComputationStatus } from '../../services/study/study';
import { useAllComputingStatusAtOnce } from './use-computing-status-at-once';

// status invalidations
const loadFlowStatusInvalidations = [NotificationType.LOADFLOW_STATUS, NotificationType.LOADFLOW_FAILED];
Expand Down Expand Up @@ -76,6 +78,34 @@ const stateEstimationStatusInvalidations = [
const pccMinStatusInvalidations = [NotificationType.PCC_MIN_STATUS, NotificationType.PCC_MIN_FAILED];

// status completions
export function getCompletions(computingType: ComputingType) {
switch (computingType) {
case ComputingType.PCC_MIN:
return pccMinStatusCompletions;
case ComputingType.LOAD_FLOW:
return loadFlowStatusCompletions;
case ComputingType.SECURITY_ANALYSIS:
return securityAnalysisStatusCompletions;
case ComputingType.SENSITIVITY_ANALYSIS:
return sensitivityAnalysisStatusCompletions;
case ComputingType.SHORT_CIRCUIT:
return shortCircuitAnalysisStatusCompletions;
case ComputingType.SHORT_CIRCUIT_ONE_BUS:
return oneBusShortCircuitAnalysisStatusCompletions;
case ComputingType.DYNAMIC_SIMULATION:
return dynamicSimulationStatusCompletions;
case ComputingType.DYNAMIC_SECURITY_ANALYSIS:
return dynamicSecurityAnalysisStatusCompletions;
case ComputingType.DYNAMIC_MARGIN_CALCULATION:
return dynamicMarginCalculationStatusCompletions;
case ComputingType.VOLTAGE_INITIALIZATION:
return voltageInitStatusCompletions;
case ComputingType.STATE_ESTIMATION:
return stateEstimationStatusCompletions;
default:
return [];
}
}
const loadFlowStatusCompletions = [NotificationType.LOADFLOW_RESULT, NotificationType.LOADFLOW_FAILED];
const securityAnalysisStatusCompletions = [
NotificationType.SECURITY_ANALYSIS_RESULT,
Expand Down Expand Up @@ -277,4 +307,12 @@ export const useAllComputingStatus = (studyUuid: UUID, currentNodeUuid: UUID, cu
undefined,
pccMinAvailability
);

useAllComputingStatusAtOnce(
studyUuid,
currentNodeUuid,
currentRootNetworkUuid,
fetchAllComputationStatus,
getCompletions
);
};
236 changes: 236 additions & 0 deletions src/components/computing-status/use-computing-status-at-once.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,236 @@
/**
* Copyright (c) 2023, 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/.
*/

import { RunningStatus } from 'components/utils/running-status';
import type { UUID } from 'node:crypto';
import { RefObject, useCallback, useEffect, useRef } from 'react';
import { useDispatch } from 'react-redux';
import { ComputingType, NotificationsUrlKeys, useNotificationsListener } from '@gridsuite/commons-ui';
import { setComputingStatus, setComputingStatusParameters, setLastCompletedComputation } from '../../redux/actions';
import { AppDispatch } from '../../redux/store';
import { isParameterizedComputingType, toComputingStatusParameters } from './computing-status-utils';
import { NotificationType, parseEventData, StudyUpdatedEventData } from '../../types/notification-types';

Check warning on line 16 in src/components/computing-status/use-computing-status-at-once.ts

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

'StudyUpdatedEventData' is deprecated.

See more on https://sonarcloud.io/project/issues?id=gridsuite_gridstudy-app&issues=AZzcYFbRYb1nM1CjMtiS&open=AZzcYFbRYb1nM1CjMtiS&pullRequest=3796
import {
AllComputationStatusInfos,
getComputingStatusParametersFetcher,
getRunningStatusByComputingType,
} from '../../services/study/study';

interface UseComputingStatusProps {
(
studyUuid: UUID,
nodeUuid: UUID,
currentRootNetworkUuid: UUID,
computingStatusFetcher: (
studyUuid: UUID,
nodeUuid: UUID,
currentRootNetworkUuid: UUID
) => Promise<AllComputationStatusInfos | null>,
getCompletions: (computingType: ComputingType) => NotificationType[]
): void;

Check warning on line 34 in src/components/computing-status/use-computing-status-at-once.ts

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Interface has only a call signature, you should use a function type instead.

See more on https://sonarcloud.io/project/issues?id=gridsuite_gridstudy-app&issues=AZzcYFbRYb1nM1CjMtiT&open=AZzcYFbRYb1nM1CjMtiT&pullRequest=3796
}

interface LastUpdateProps {
eventData: StudyUpdatedEventData | null;

Check warning on line 38 in src/components/computing-status/use-computing-status-at-once.ts

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

'StudyUpdatedEventData' is deprecated.

See more on https://sonarcloud.io/project/issues?id=gridsuite_gridstudy-app&issues=AZzcYFbRYb1nM1CjMtiU&open=AZzcYFbRYb1nM1CjMtiU&pullRequest=3796
allComputingStatusFetcher: (
studyUuid: UUID,
nodeUuid: UUID,
currentRootNetworkUuid: UUID
) => Promise<AllComputationStatusInfos | null>;
}

function isWorthUpdate(
nodeUuidRef: RefObject<UUID | null>,
rootNetworkUuidRef: RefObject<UUID | null>,
nodeUuid: UUID,
currentRootNetworkUuid: UUID
): boolean {
if (nodeUuidRef.current !== nodeUuid) {
return true;
}
return rootNetworkUuidRef.current !== currentRootNetworkUuid;
}

const shouldRequestBeCanceled = (
canceledRequest: boolean,
previousNodeUuid: UUID,
currentNodeUuid: UUID,
previousRootNetworkUuid: UUID,
currentRootNetworkUuid: UUID
) => {
return (
canceledRequest || previousNodeUuid !== currentNodeUuid || previousRootNetworkUuid !== currentRootNetworkUuid
);
};

/**
* this hook loads <computingType> state into redux, then keeps it updated according to notifications
* @param studyUuid current study uuid
* @param nodeUuid current node uuid
* @param allComputingStatusFetcher method fetching all <computingType> state
* @param currentRootNetworkUuid
* @param getCompletions
*/
export const useAllComputingStatusAtOnce: UseComputingStatusProps = (
studyUuid,
nodeUuid,
currentRootNetworkUuid,
allComputingStatusFetcher,
getCompletions
) => {
const nodeUuidRef = useRef<UUID | null>(null);
const rootNetworkUuidRef = useRef<UUID | null>(null);
const lastUpdateRef = useRef<LastUpdateProps | null>(null);
const dispatch = useDispatch<AppDispatch>();

//the callback crosschecks the computation status and the content of the last update reference
//in order to determine which computation just ended
const isComputationCompleted = useCallback((status: RunningStatus, completions: string[]) => {
const eventData = lastUpdateRef.current?.eventData;
return (
[RunningStatus.FAILED, RunningStatus.SUCCEED].includes(status) &&
completions.includes(eventData?.headers?.updateType ?? '')
);
}, []);

const handleComputingStatusParameters = useCallback(
async (
computationStatus: RunningStatus,
canceledRequest: boolean,
computingType: ComputingType,
computingStatusParametersFetcher:
| ((studyUuid: UUID, nodeUuid: UUID, currentRootNetworkUuid: UUID) => Promise<string | null>)
| undefined
) => {
if (
computingStatusParametersFetcher &&
computationStatus !== RunningStatus.IDLE &&
isParameterizedComputingType(computingType)
) {
nodeUuidRef.current = nodeUuid;
rootNetworkUuidRef.current = currentRootNetworkUuid;
const computingStatusParametersResult = await computingStatusParametersFetcher(
studyUuid,
nodeUuid,
currentRootNetworkUuid
);
if (
shouldRequestBeCanceled(
canceledRequest,
nodeUuidRef.current,
nodeUuid,
rootNetworkUuidRef.current,
currentRootNetworkUuid
)
) {
return;
}
dispatch(
setComputingStatusParameters(
computingType,
toComputingStatusParameters(computingStatusParametersResult, computingType)
)
);
}
},
[currentRootNetworkUuid, dispatch, nodeUuid, studyUuid]
);

const update = useCallback(async () => {
// this is used to prevent race conditions from happening
// if another request is sent, the previous one won't do anything
let canceledRequest = false;

//upon changing node we reset the last completed computation to prevent results misredirection
dispatch(setLastCompletedComputation());

nodeUuidRef.current = nodeUuid;
rootNetworkUuidRef.current = currentRootNetworkUuid;
try {
// fetch computing status
const computingStatusResult: AllComputationStatusInfos | null = await allComputingStatusFetcher(
studyUuid,
nodeUuid,
currentRootNetworkUuid
);
if (
shouldRequestBeCanceled(
canceledRequest,
nodeUuidRef.current,
nodeUuid,
rootNetworkUuidRef.current,
currentRootNetworkUuid
)
) {
return;
}
// if request has not been canceled for any reason, fetch if necessary computingStatusParameters
const allStatusInfos = computingStatusResult;
if (allStatusInfos != null) {
// for each status
for (const computingType of Object.values(ComputingType)) {
const status = getRunningStatusByComputingType(allStatusInfos, computingType);
dispatch(setComputingStatus(computingType, status));
if (isComputationCompleted(status, getCompletions(computingType))) {
dispatch(setLastCompletedComputation(computingType));
}
await handleComputingStatusParameters(
status,
canceledRequest,
computingType,
getComputingStatusParametersFetcher(computingType)
);
}
}
} catch (e: any) {
if (!canceledRequest) {
// for each status
for (const computingType of Object.values(ComputingType)) {
dispatch(setComputingStatus(computingType, RunningStatus.FAILED));
console.error(e?.message);
}
}
}

return () => {
canceledRequest = true;
};
}, [
getCompletions,
dispatch,
nodeUuid,
currentRootNetworkUuid,
allComputingStatusFetcher,
studyUuid,
handleComputingStatusParameters,
isComputationCompleted,
]);

const evaluateUpdate = useCallback(
(event?: MessageEvent) => {
if (!studyUuid || !nodeUuid || !currentRootNetworkUuid) {
return;
}
const eventData = parseEventData<StudyUpdatedEventData>(event ?? null);

Check warning on line 218 in src/components/computing-status/use-computing-status-at-once.ts

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

'StudyUpdatedEventData' is deprecated.

See more on https://sonarcloud.io/project/issues?id=gridsuite_gridstudy-app&issues=AZzcYFbRYb1nM1CjMtiV&open=AZzcYFbRYb1nM1CjMtiV&pullRequest=3796
const isUpdateForUs = isWorthUpdate(nodeUuidRef, rootNetworkUuidRef, nodeUuid, currentRootNetworkUuid);
lastUpdateRef.current = { eventData, allComputingStatusFetcher };
if (isUpdateForUs) {
update();
}
},
[allComputingStatusFetcher, currentRootNetworkUuid, nodeUuid, studyUuid, update]
);

useNotificationsListener(NotificationsUrlKeys.STUDY, {
listenerCallbackMessage: evaluateUpdate,
});

/* initial fetch and update */
useEffect(() => {
evaluateUpdate();
}, [evaluateUpdate]);
};
6 changes: 0 additions & 6 deletions src/components/computing-status/use-computing-status.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,12 +59,6 @@ function isWorthUpdate(
const node = headers?.node;
const nodes = headers?.nodes;
const rootNetworkUuidFromNotification = headers?.rootNetworkUuid;
if (nodeUuidRef.current !== nodeUuid) {
return true;
}
if (rootNetworkUuidRef.current !== currentRootNetworkUuid) {
return true;
}
if (rootNetworkUuidFromNotification && rootNetworkUuidFromNotification !== currentRootNetworkUuid) {
return false;
}
Expand Down
Loading
Loading