From c93c4627d0e589351b5da92f5c1c9cb85ccc5eb7 Mon Sep 17 00:00:00 2001 From: Gabriel Almeida Date: Fri, 19 May 2023 10:07:13 -0300 Subject: [PATCH] feat(typesContext.tsx): add retry logic to getAll API call This commit adds retry logic to the getAll API call in the TypesProvider component. The retry logic will attempt to make the API call up to 5 times with an increasing delay between each attempt. If the API call is successful, the state of the component will be updated with the retrieved data. If the component is unmounted before the API call resolves, the state will not be updated. --- src/frontend/src/contexts/typesContext.tsx | 92 +++++++++++++++------- 1 file changed, 63 insertions(+), 29 deletions(-) diff --git a/src/frontend/src/contexts/typesContext.tsx b/src/frontend/src/contexts/typesContext.tsx index 000bfa472..f0f765bb6 100644 --- a/src/frontend/src/contexts/typesContext.tsx +++ b/src/frontend/src/contexts/typesContext.tsx @@ -27,37 +27,71 @@ export function TypesProvider({ children }: { children: ReactNode }) { const [data, setData] = useState({}); useEffect(() => { - async function getTypes(): Promise { - // Make an asynchronous API call to retrieve all data. - let result = await getAll(); + let delay = 1000; // Start delay of 1 second + let intervalId = null; + let retryCount = 0; // Count of retry attempts + const maxRetryCount = 5; // Max retry attempts - // Update the state of the component with the retrieved data. - setData(result.data); - setTemplates( - Object.keys(result.data).reduce((acc, curr) => { - Object.keys(result.data[curr]).forEach((c: keyof APIKindType) => { - acc[c] = result.data[curr][c]; - }); - return acc; - }, {}) - ); - // Set the types by reducing over the keys of the result data and updating the accumulator. - setTypes( - Object.keys(result.data).reduce((acc, curr) => { - Object.keys(result.data[curr]).forEach((c: keyof APIKindType) => { - acc[c] = curr; - // Add the base classes to the accumulator as well. - result.data[curr][c].base_classes?.forEach((b) => { - acc[b] = curr; - }); - }); - return acc; - }, {}) - ); + // We will keep a flag to handle the case where the component is unmounted before the API call resolves. + let isMounted = true; + + async function getTypes(): Promise { + try { + const result = await getAll(); + // Make sure to only update the state if the component is still mounted. + if (isMounted) { + // Continue with your logic... + setData(result.data); + setTemplates( + Object.keys(result.data).reduce((acc, curr) => { + Object.keys(result.data[curr]).forEach((c: keyof APIKindType) => { + acc[c] = result.data[curr][c]; + }); + return acc; + }, {}) + ); + // Set the types by reducing over the keys of the result data and updating the accumulator. + setTypes( + Object.keys(result.data).reduce((acc, curr) => { + Object.keys(result.data[curr]).forEach((c: keyof APIKindType) => { + acc[c] = curr; + // Add the base classes to the accumulator as well. + result.data[curr][c].base_classes?.forEach((b) => { + acc[b] = curr; + }); + }); + return acc; + }, {}) + ); + } + // Clear the interval if successful. + clearInterval(intervalId); + } catch (error) { + retryCount++; + // On error, double the delay for the next attempt up to a maximum. + delay = Math.min(30000, delay * 2); + // Log errors but don't do anything else - the function will try again on the next interval. + console.error(error); + // Clear the old interval and start a new one with the new delay. + if (retryCount <= maxRetryCount) { + clearInterval(intervalId); + intervalId = setInterval(getTypes, delay); + } else { + console.error("Max retry attempts reached. Stopping retries."); + } + } } - // Call the getTypes function. - getTypes(); - }, [setTypes]); + + // Start the initial interval. + intervalId = setInterval(getTypes, delay); + + return () => { + // This will clear the interval when the component unmounts, or when the dependencies of the useEffect hook change. + clearInterval(intervalId); + // Indicate that the component has been unmounted. + isMounted = false; + }; + }, []); function deleteNode(idx: string) { reactFlowInstance.setNodes(