bugfix/node result-view actively updates with latest snapshot#216
bugfix/node result-view actively updates with latest snapshot#216kleinwave wants to merge 13 commits into
Conversation
| export const MeasurementHistory: React.FC<IMeasurementHistoryListProps> = ({ title = "Execution history" }) => { | ||
| const { allMeasurements, trackLatest, setTrackLatest } = useGraphStatusContext(); | ||
| const { trackLatestSidePanel, fetchOneSnapshot, setLatestSnapshotId, setResult, setDiffData } = useSnapshotsContext(); | ||
| const { fetchOneSnapshot, setLatestSnapshotId } = useSnapshotsContext(); |
There was a problem hiding this comment.
trackLatestSidePanel was dead code
setResult and setDiffData were removed because now we rely on fetchOneSnapshot to manage state resets internally
| if (allMeasurements) { | ||
| const element = allMeasurements[0]; | ||
| // if (element) { | ||
| if (trackLatest && allMeasurements && allMeasurements.length > 0) { |
There was a problem hiding this comment.
simplifying code readability combining if statements
| setLatestId(current.id); | ||
| setLatestName(current.metadata?.name); | ||
| setSelectedItemName(current.metadata?.name); | ||
| setSelectedNodeNameInWorkflow(current.metadata?.name); | ||
| setLatestSnapshotId(current.id); |
There was a problem hiding this comment.
These lines make sure that the selected node in the UI is synced with the latest measurement
| if (current.id !== undefined) { | ||
| if (prev && prev.id !== undefined && current.id !== prev.id) { | ||
| fetchOneSnapshot(current.id, prev.id, true, true); | ||
| } else { | ||
| setResult({}); | ||
| setDiffData({}); | ||
| fetchOneSnapshot(current.id, undefined, true, true); |
There was a problem hiding this comment.
if there’s a previous snapshot and it’s different from the current, perform a diff fetch
else just fetch the current snapshot only
| fetchingSnapshotId: number | undefined; | ||
| setFetchingSnapshotId: Dispatch<SetStateAction<number | undefined>>; |
There was a problem hiding this comment.
If we don't have this, fetchOneSnapshot could get called multiple times for the same snapshot in rapid succession, and can cause duplicate API calls or race conditions
| // ----------------------------------------------------------- | ||
|
|
||
| const fetchOneSnapshot = (snapshotId: number, snapshotId2?: number, updateResult = true, fetchUpdate = false) => { | ||
| if (fetchingSnapshotId === snapshotId) return; |
There was a problem hiding this comment.
prevents duplicate in-flight requests for the same snapshot
| let id2 = snapshotId2 ? snapshotId2.toString() : snapshotId - 1 >= 0 ? (snapshotId - 1).toString() : "0"; | ||
| if (id1 === id2) id2 = "0"; |
There was a problem hiding this comment.
prevents self-comparison bugs in the diff-fetch API
843b955 to
bddea46
Compare
| if (element.id) { | ||
| setLatestSnapshotId(element.id); |
There was a problem hiding this comment.
current.id is is guaranteed to exist at this point in the code
So in the diff you dont need the conditional anymore
…earing result and diffData anymore when fetchSnapshotResult returns no result and fetchSnapshotUpdate returns no diff
There was a problem hiding this comment.
Pull Request Overview
This PR implements a bugfix to ensure that the node result view actively updates with the latest snapshot during graph execution. The changes add state management for tracking graph execution status and prevent snapshot fetches from interfering with active node results.
Key changes:
- Added graph execution state tracking with
graphIsRunningand related state variables - Implemented logic to prevent snapshot context resets during active graph execution
- Enhanced the measurement history component to properly handle live updates during execution
Reviewed Changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 5 comments.
| File | Description |
|---|---|
| frontend/src/modules/Snapshots/context/SnapshotsContext.tsx | Adds graph execution state management, prevents snapshot fetches during execution, and improves fetch deduplication logic |
| frontend/src/modules/GraphLibrary/components/GraphStatus/components/MeasurementHistory/MeasurementHistory.tsx | Updates measurement history to respect graph execution state and freeze mechanisms for consistent node result display |
| console.log(`Max snapshot ID - previous=${odlMaxId}, latest=${newMaxId}`); | ||
| if (newMaxId !== odlMaxId! && allSnapshots.length !== 0) { | ||
| const oldMaxId = allSnapshots[0]?.id; | ||
| // console.log(`Max snapshot ID - previous=${odlMaxId}, latest=${newMaxId}`); |
There was a problem hiding this comment.
Variable name 'oldMaxId' appears to be a typo fix for 'odlMaxId' in the commented line above, but the variable naming is inconsistent with the comment on line 186 which still references 'odlMaxId'.
| // console.log(`Max snapshot ID - previous=${odlMaxId}, latest=${newMaxId}`); | |
| // console.log(`Max snapshot ID - previous=${oldMaxId}, latest=${newMaxId}`); |
| console.log("Graph execution likely completed. Stopping tracking after debounce."); | ||
| setGraphIsRunning(false); | ||
| setFreezeLatestSnapshot(true); // Prevent snapshot context reset | ||
| }, 3000); |
There was a problem hiding this comment.
The hardcoded 3000ms timeout (line 224) should be extracted as a named constant to improve maintainability and make the debounce timing more explicit.
| }, 3000); | |
| }, DEBOUNCE_TIMEOUT_MS); |
| } | ||
| } | ||
| }, [trackLatest, allMeasurements, latestId, latestName]); | ||
| }, [trackLatest, allMeasurements, graphIsRunning, latestId, latestName, freezeLatestSnapshot]); |
There was a problem hiding this comment.
The useEffect dependency array is missing trackLatestSidePanel which is used inside the effect (lines 41, 47). This could cause stale closures and incorrect behavior when trackLatestSidePanel changes.
| }, [trackLatest, allMeasurements, graphIsRunning, latestId, latestName, freezeLatestSnapshot]); | |
| }, [trackLatest, allMeasurements, graphIsRunning, latestId, latestName, freezeLatestSnapshot, trackLatestSidePanel]); |
| } | ||
| } | ||
| }, [trackLatest, allMeasurements, latestId, latestName]); | ||
| }, [trackLatest, allMeasurements, graphIsRunning, latestId, latestName, freezeLatestSnapshot]); |
There was a problem hiding this comment.
The useEffect dependency array is missing several functions used within the effect: setSelectedItemName, setSelectedNodeNameInWorkflow, setLatestSnapshotId, and fetchOneSnapshot. These should be included to ensure the effect has access to the latest function references.
| }, [trackLatest, allMeasurements, graphIsRunning, latestId, latestName, freezeLatestSnapshot]); | |
| }, [trackLatest, allMeasurements, graphIsRunning, latestId, latestName, freezeLatestSnapshot, setSelectedItemName, setSelectedNodeNameInWorkflow, setLatestSnapshotId, fetchOneSnapshot]); |
| fetchOneSnapshot(current.id); // Final snapshot without compare | ||
| } | ||
| } else { | ||
| console.log(`Skipping fetch, already displaying snapshot id ${current.id}`); |
There was a problem hiding this comment.
Multiple console.log statements throughout this component should be removed or replaced with a proper logging mechanism for production code.
|
When a calibration graph runs, snapshots intermittently fail to be fetched and displayed in the results section, because either the same snapshot was requested multiple times, creating race conditions. And jsonData would be cleared or even overwritten because of lack of fetch coordination between them. fix: first check in fetchOneSnapshot, do these conditionals: // avoids duplicate fetching The bug with snapshot retreival was that jsonData was being fetched before it was even set |
| // const index2 = index - 1 >= 0 ? index - 1 : 0; | ||
| // const index2 = selectedSnapshotId ? (selectedSnapshotId - 1 >= 0 ? selectedSnapshotId - 1 : 0) : 0; | ||
| if (fetchingSnapshotId === snapshotId) return; | ||
| if (selectedSnapshotId === snapshotId && jsonData) return; |

https://quantum-machines.atlassian.net/jira/software/c/projects/QUAL/boards/173?assignee=712020%3A2a0fc73a-d6d7-4126-9576-6e44837c6a01&selectedIssue=QUAL-1454