Skip to content

Commit f8ab86d

Browse files
Merge pull request #170 from alanconway/useeffect-race
NO-JIRA: fix: Reduce useEffect dependencies to avoid cancelled requests.
2 parents 2da72ca + 1c02e11 commit f8ab86d

2 files changed

Lines changed: 45 additions & 55 deletions

File tree

web/locales/en/plugin__troubleshooting-panel-console-plugin.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,14 @@
22
"Advanced": "Advanced",
33
"Ago": "Ago",
44
"Correlation result was empty.": "Correlation result was empty.",
5-
"Create a graph of correlated items from resources in the current view.": "Create a graph of correlated items from resources in the curret view.",
5+
"Create a graph of items correlated from resources in the current page.": "Create a graph of items correlated from resources in the current page.",
66
"Distance": "Distance",
77
"Find all paths to items of the specified goal class.": "Find all paths to items of the specified goal class.",
88
"Focus": "Focus",
99
"Follows correlation rules from the starting point to find related data, then continues the search from that data, up to the number of steps you specify.": "Follows correlation rules from the starting point to find related data, then continues the search from that data, up to the number of steps you specify.",
1010
"Goal Class": "Goal Class",
1111
"Korrel8r Error": "Korrel8r Error",
12+
"Loading": "Loading",
1213
"Logging Plugin Disabled": "Logging Plugin Disabled",
1314
"Netflow Plugin Disabled": "Netflow Plugin Disabled",
1415
"No Correlated Signals Found": "No Correlated Signals Found",
@@ -24,7 +25,7 @@
2425
"Search Type": "Search Type",
2526
"Selects the starting point for correlation search. This query is set automatically by the <1>Focus</1> button. You can edit it manually to specify a custom query.": "Selects the starting point for correlation search. This query is set automatically by the <1>Focus</1> button. You can edit it manually to specify a custom query.",
2627
"Since": "Since",
27-
"The current view does not support correlation.": "The current view does not support correlation.",
28+
"The current page does not support correlation.": "The current page does not support correlation.",
2829
"Time": "Time",
2930
"to": "to",
3031
"Troubleshooting": "Troubleshooting",

web/src/components/Korrel8rPanel.tsx

Lines changed: 42 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,6 @@ export default function Korrel8rPanel() {
5151
});
5252
const dispatch = useDispatch();
5353

54-
// State
5554
const alertRules = useSelector((state: State) => state.observe?.get('rules'));
5655
const alertIDs = React.useMemo(() => {
5756
if (!alertRules) return new Map<string, string>();
@@ -62,79 +61,67 @@ export default function Korrel8rPanel() {
6261
[alertIDs],
6362
);
6463
const locationQuery = useLocationQuery(domains);
64+
65+
// Search parameters.
6566
const [search, setSearch] = React.useState<Search>({
6667
...defaultSearch, // Default search parameters.
67-
queryStr: locationQuery?.toString(), // Default query string.
68+
queryStr: locationQuery?.toString(), // Default query string from location.
6869
...searchResult?.search, // Use persisted search if available.
6970
});
71+
// Search result
7072
const [result, setResult] = React.useState<Result | null>(searchResult?.result ?? null);
73+
// Showing advanced query
7174
const [showQuery, setShowQuery] = React.useState(false);
7275

73-
const focusTip = t('Create a graph of correlated items from resources in the current view.');
74-
const cannotFocus = t('The current view does not support correlation.');
75-
7676
React.useEffect(() => {
77-
// Set result = null to trigger a new client request, don't run the query till then.
78-
if (result !== null) {
79-
return;
80-
}
81-
if (!search?.queryStr && !locationQuery) {
82-
setResult({ message: cannotFocus });
83-
return;
84-
}
8577
// eslint-disable-next-line no-console
8678
console.debug('korrel8r search', search);
8779
const queryStr = search?.queryStr?.trim();
8880
const start: api.Start = {
8981
queries: queryStr ? [queryStr] : undefined,
9082
constraint: search?.constraint?.toAPI() ?? undefined,
9183
};
92-
const cancellableFetch =
84+
let cancelled = false; // Detect if returned cleanup function was called.
85+
const onResult = (newResult: Result) => {
86+
if (!cancelled) {
87+
setResult(newResult);
88+
dispatch(setPersistedSearch({ search, result: newResult }));
89+
}
90+
// eslint-disable-next-line no-console
91+
console.debug('korrel8r result', newResult, 'cancelled', cancelled);
92+
};
93+
const fetch =
9394
search.type === SearchType.Goal
9495
? getGoalsGraph({ start, goals: [search.goal] })
9596
: getNeighborsGraph({ start, depth: search.depth });
96-
97-
cancellableFetch
98-
.then((response: api.Graph) => {
99-
const result: Result = { graph: new korrel8r.Graph(response) };
100-
// eslint-disable-next-line no-console
101-
console.debug('korrel8r result', result);
102-
setResult(result);
103-
dispatch(setPersistedSearch({ search, result }));
104-
})
97+
fetch
98+
.then((response: api.Graph) => onResult({ graph: new korrel8r.Graph(response) }))
10599
.catch((e: api.ApiError) => {
106-
const result = {
107-
message: e.body?.error || e.message || 'Unknown Error',
100+
onResult({
108101
title: e?.body?.error ? t('Korrel8r Error') : t('Request Failed'),
109-
};
110-
// eslint-disable-next-line no-console
111-
console.debug('korrel8r result', result);
112-
setResult(result);
113-
dispatch(setPersistedSearch({ search, result }));
102+
message: e?.body?.error || e.message || 'Unknown Error',
103+
});
114104
});
115-
return () => cancellableFetch.cancel();
116-
}, [result, t, dispatch, search, cannotFocus, locationQuery]);
105+
return () => {
106+
cancelled = true;
107+
fetch.cancel();
108+
};
109+
}, [search, t, dispatch]);
117110

118111
const queryToggleID = 'query-toggle';
119112
const queryContentID = 'query-content';
120113
const queryInputID = 'query-input';
121114

122-
const depthBounds = applyBounds(1, 10);
123-
124-
const runSearch = React.useCallback(
125-
(newSearch: Search) => {
126-
// Update constraint from time period
127-
if (newSearch.period) {
128-
const [start, end] = newSearch.period.startEnd();
129-
newSearch.constraint = new korrel8r.Constraint({ ...newSearch.constraint, start, end });
130-
}
131-
newSearch.depth = depthBounds(newSearch.depth);
132-
newSearch.type = !newSearch.goal ? SearchType.Distance : newSearch.type;
133-
setSearch(newSearch);
134-
setResult(null);
135-
},
136-
[setResult, depthBounds],
137-
);
115+
const runSearch = React.useCallback((newSearch: Search) => {
116+
// Update constraint from time period
117+
if (newSearch.period) {
118+
const [start, end] = newSearch.period.startEnd();
119+
newSearch.constraint = new korrel8r.Constraint({ ...newSearch.constraint, start, end });
120+
}
121+
newSearch.depth = Math.max(1, Math.min(newSearch.depth, 10));
122+
setSearch({ ...newSearch }); // Create a new search object to trigger useEffect
123+
setResult(null);
124+
}, []);
138125

139126
const queryHelp = (
140127
<>
@@ -153,7 +140,13 @@ export default function Korrel8rPanel() {
153140
);
154141

155142
const focusButton = (
156-
<Tooltip content={locationQuery ? focusTip : cannotFocus}>
143+
<Tooltip
144+
content={
145+
locationQuery
146+
? t('Create a graph of items correlated from resources in the current page.')
147+
: t('The current page does not support correlation.')
148+
}
149+
>
157150
<Button
158151
isAriaDisabled={!locationQuery}
159152
onClick={() => {
@@ -346,7 +339,3 @@ const TopologyInfoState: React.FC<TopologyInfoStateProps> = ({ titleText, text,
346339
</div>
347340
);
348341
};
349-
350-
const applyBounds = (min: number, max: number) => {
351-
return (val: number) => Math.max(min, Math.min(val, max));
352-
};

0 commit comments

Comments
 (0)