Skip to content

Commit d897c58

Browse files
ryanjdewMarkLogic Builder
authored andcommitted
DHFPROD-7672: Avoid repeating search calls on errors
1 parent 687975b commit d897c58

File tree

3 files changed

+146
-78
lines changed

3 files changed

+146
-78
lines changed

marklogic-data-hub-central/ui/src/components/tiles/tiles.tsx

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React, {useContext, useEffect, useState} from "react";
1+
import React, {useContext, useEffect, useRef, useState} from "react";
22
import {Mosaic, MosaicWindow} from "react-mosaic-component";
33
import "react-mosaic-component/react-mosaic-component.css";
44
import {ArrowsAltOutlined, ShrinkOutlined, CloseOutlined} from "@ant-design/icons";
@@ -27,7 +27,7 @@ interface Props {
2727
}
2828

2929
const Tiles: React.FC<Props> = (props) => {
30-
30+
const componentIsMounted = useRef(true);
3131
const options = props.options;
3232
const controls = props.options.controls;
3333
const viewId = props.id;
@@ -84,8 +84,8 @@ const Tiles: React.FC<Props> = (props) => {
8484

8585
const getEntities = async () => {
8686
try {
87-
const res= await primaryEntityTypes();
88-
if (res) {
87+
const res = await primaryEntityTypes();
88+
if (res && componentIsMounted.current) {
8989
if (res.data.length === 0) setModelingInfoVisible(true);
9090
}
9191
} catch (error) {
@@ -107,6 +107,7 @@ const Tiles: React.FC<Props> = (props) => {
107107

108108
useEffect(() => {
109109
getEntities();
110+
return () => { componentIsMounted.current = false; };
110111
}, []);
111112

112113
const modelingInfoViewChange = (visible) => {

marklogic-data-hub-central/ui/src/pages/Detail.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,9 +62,9 @@ const Detail: React.FC<Props> = ({history, location}) => {
6262

6363
const getSaveQueries = async () => {
6464
try {
65-
if (authorityService.isSavedQueryUser()) {
65+
if (componentIsMounted.current && authorityService.isSavedQueryUser()) {
6666
const response = await fetchQueries();
67-
if (response.data) {
67+
if (componentIsMounted.current && response.data) {
6868
setSavedQueries(response.data);
6969
}
7070
}

marklogic-data-hub-central/ui/src/util/user-context.tsx

Lines changed: 139 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,8 @@ export const UserContext = React.createContext<IUserContextInterface>({
5757
});
5858

5959
const UserProvider: React.FC<{ children: any }> = ({children}) => {
60-
6160
const [user, setUser] = useState<UserContextInterface>(defaultUserData);
61+
const [encounteredErrors, setEncounteredErrors] = useState<string[]>([]);
6262
const [stompMessageSubscription, setStompMessageSubscription] = useState<Subscription|null>(null);
6363
const [unsubscribeId, setUnsubscribeId] = useState<string|null>(null);
6464
const sessionUser = localStorage.getItem("dataHubUser");
@@ -68,6 +68,37 @@ const UserProvider: React.FC<{ children: any }> = ({children}) => {
6868
initialTimeoutDate.setSeconds(initialTimeoutDate.getSeconds() + MAX_SESSION_TIME);
6969
const sessionTimeoutDate = useRef<Date>(initialTimeoutDate);
7070

71+
const getConfigHash = (config) => {
72+
return CryptoJS.SHA256(`${config.method}:${config.url}:${config.data}`).toString();
73+
};
74+
75+
axios.interceptors.request.use(
76+
request => {
77+
if (request) {
78+
const requestHash = getConfigHash(request);
79+
if (encounteredErrors.includes(requestHash)) {
80+
throw new axios.Cancel(requestHash);
81+
}
82+
}
83+
return request;
84+
},
85+
error => {
86+
if (error instanceof axios.Cancel && encounteredErrors.includes(error.message)) {
87+
return new Promise(r => setTimeout(r, 5000)).then(
88+
(r) => {
89+
// forget the error after 5 seconds.
90+
if (encounteredErrors.includes(error.message)) {
91+
encounteredErrors.splice(encounteredErrors.indexOf(error.message), 1);
92+
setEncounteredErrors(encounteredErrors);
93+
}
94+
return r;
95+
}
96+
);
97+
}
98+
return Promise.reject(error);
99+
}
100+
);
101+
71102
const setSessionTimeoutDate = (timeInSeconds) => {
72103
const timeoutDate = new Date();
73104
timeoutDate.setSeconds(timeoutDate.getSeconds() + timeInSeconds);
@@ -202,94 +233,130 @@ const UserProvider: React.FC<{ children: any }> = ({children}) => {
202233
localStorage.setItem("loginResp", "");
203234
localStorage.setItem("hubCentralSessionToken", "");
204235
authoritiesService.setAuthorities([]);
236+
setEncounteredErrors([]);
205237
resetEnvironment();
206238
});
207239
};
208240

241+
/*
242+
* handleError - A consistent way to handle and present errors.
243+
* @param error - The error response which we will decide to handle an error
244+
* */
209245
const handleError = (error) => {
210246
const DEFAULT_MESSAGE = "Internal Server Error";
211-
switch (error.response.status) {
212-
case 401: {
213-
localStorage.setItem("dataHubUser", "");
214-
localStorage.setItem("loginResp", "");
215-
setUser({...user, name: "", authenticated: false});
216-
break;
217-
}
218-
case 400:
219-
case 403:
220-
case 405:
221-
case 408:
222-
case 414: {
223-
console.error("HTTP ERROR", error.response);
224-
let title = error.response.status + " " + error.response.statusText;
225-
let message = DEFAULT_MESSAGE;
226-
227-
if (error.response.data.hasOwnProperty("message")) {
228-
message = error.response.data.message;
247+
let errorHash = "";
248+
let errorAlreadyEncountered = false;
249+
if (error.config && error.response && error.response.status >= 500) {
250+
let config = error.config;
251+
errorHash = getConfigHash(config);
252+
errorAlreadyEncountered = encounteredErrors.includes(errorHash);
253+
if (!errorAlreadyEncountered) {
254+
console.warn("Request error will cause future exact requests to be canceled for the next 5 seconds.");
255+
encounteredErrors.push(errorHash);
256+
setEncounteredErrors(encounteredErrors);
229257
}
230-
setUser({
231-
...user,
232-
error: {
233-
title: title,
234-
message: message,
235-
type: "ALERT"
236-
}
237-
});
238-
break;
239258
}
240-
case 404: {
241-
setUser({
242-
...user,
243-
// redirect: true,
244-
error: {
245-
title: error.response.data.error,
246-
message: error.response.data.message || DEFAULT_MESSAGE,
247-
type: "ALERT"
259+
if (!errorAlreadyEncountered) {
260+
if (error.response) {
261+
switch (error.response.status) {
262+
case 401: {
263+
localStorage.setItem("dataHubUser", "");
264+
localStorage.setItem("loginResp", "");
265+
setUser({...user, name: "", authenticated: false});
266+
break;
248267
}
249-
});
250-
break;
251-
}
252-
case 500:
253-
case 501:
254-
case 502:
255-
case 503:
256-
case 504:
257-
case 505:
258-
case 511: {
259-
console.error("HTTP ERROR ", error.response);
260-
let title = error.response.status + " " + error.response.statusText;
261-
let message = DEFAULT_MESSAGE;
268+
case 400:
269+
case 403:
270+
case 405:
271+
case 408:
272+
case 414: {
273+
console.error("HTTP ERROR", error.response);
274+
let title = error.response.status + " " + error.response.statusText;
275+
let message = DEFAULT_MESSAGE;
262276

263-
if (error.response.data.hasOwnProperty("message")) {
264-
message = error.response.data.message;
265-
}
266-
setUser({
267-
...user,
268-
error: {
269-
title,
270-
message,
271-
type: "MODAL"
277+
if (error.response.data.hasOwnProperty("message")) {
278+
message = error.response.data.message;
279+
}
280+
setUser({
281+
...user,
282+
error: {
283+
title: title,
284+
message: message,
285+
type: "ALERT",
286+
encounteredErrors
287+
}
288+
});
289+
break;
272290
}
273-
});
274-
break;
275-
}
276-
default: {
277-
console.error("HTTP ERROR ", error.response);
291+
case 404: {
292+
setUser({
293+
...user,
294+
// redirect: true,
295+
error: {
296+
title: error.response.data.error,
297+
message: error.response.data.message || DEFAULT_MESSAGE,
298+
type: "ALERT",
299+
encounteredErrors
300+
}
301+
});
302+
break;
303+
}
304+
case 500:
305+
case 501:
306+
case 502:
307+
case 503:
308+
case 504:
309+
case 505:
310+
case 511: {
311+
console.error("HTTP ERROR ", error.response);
312+
let title = error.response.status + " " + error.response.statusText;
313+
let message = DEFAULT_MESSAGE;
278314

279-
setUser({
280-
...user,
281-
error: {
282-
title: DEFAULT_MESSAGE,
283-
message: "Please check the console for more information",
284-
type: "MODAL"
315+
if (error.response.data.hasOwnProperty("message")) {
316+
message = error.response.data.message;
317+
}
318+
setUser({
319+
...user,
320+
error: {
321+
title,
322+
message,
323+
type: "MODAL",
324+
encounteredErrors
325+
}
326+
});
327+
break;
285328
}
286-
});
287-
break;
288-
}
329+
default: {
330+
console.error("HTTP ERROR ", error.response);
331+
setUser({
332+
...user,
333+
error: {
334+
title: DEFAULT_MESSAGE,
335+
message: "Please check the console for more information",
336+
type: "MODAL",
337+
encounteredErrors
338+
}
339+
});
340+
break;
341+
}
342+
}
343+
} else {
344+
console.error("ERROR ", error);
345+
setUser({
346+
...user,
347+
error: {
348+
title: DEFAULT_MESSAGE,
349+
message: "Please check the console for more information",
350+
type: "MODAL",
351+
encounteredErrors
352+
}
353+
});
354+
}
289355
}
290356
};
291357

292358
const clearErrorMessage = () => {
359+
setEncounteredErrors([]);
293360
setUser({...user, error: {title: "", message: "", type: ""}});
294361
};
295362

0 commit comments

Comments
 (0)