Skip to content

Commit 78899a4

Browse files
committed
feat: add timeout handling for twin and serialized parts fetching to prevent infinite loading
1 parent 1033a65 commit 78899a4

File tree

2 files changed

+42
-3
lines changed

2 files changed

+42
-3
lines changed

ichub-frontend/src/features/serialized-parts/components/SerializedPartsTable.tsx

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -115,11 +115,22 @@ const SerializedPartsTable = ({ parts, onRefresh }: SerializedPartsTableProps) =
115115
const fetchTwinsOnce = useCallback(async (): Promise<SerializedPartTwinRead[]> => {
116116
console.log('Fetching all twins for general serialized parts view (once)');
117117
try {
118-
const twins = await fetchAllSerializedPartTwins();
118+
// Add timeout to prevent infinite loading on twin requests
119+
const timeoutPromise = new Promise<never>((_, reject) => {
120+
setTimeout(() => reject(new Error('Twin request timeout after 15 seconds')), 15000);
121+
});
122+
123+
const twins = await Promise.race([
124+
fetchAllSerializedPartTwins(),
125+
timeoutPromise
126+
]);
127+
119128
setAllTwins(twins);
120129
return twins;
121130
} catch (error) {
122131
console.error('Error fetching all twins:', error);
132+
// Always return empty array and clear loading state on any error
133+
setAllTwins([]);
123134
return [];
124135
}
125136
}, []); // No dependencies - this function should be stable
@@ -162,7 +173,24 @@ const SerializedPartsTable = ({ parts, onRefresh }: SerializedPartsTableProps) =
162173
if (twins.length === 0) {
163174
console.log('Fetching all twins for general serialized parts view (initial load)');
164175
setIsInitialLoading(true);
165-
twins = await fetchTwinsOnce();
176+
177+
// Add timeout for the entire twin loading process
178+
const timeoutPromise = new Promise<SerializedPartTwinRead[]>((_, reject) => {
179+
setTimeout(() => {
180+
console.warn('Twin data loading timed out after 20 seconds, proceeding without twin data');
181+
reject(new Error('Twin loading timeout'));
182+
}, 20000);
183+
});
184+
185+
try {
186+
twins = await Promise.race([
187+
fetchTwinsOnce(),
188+
timeoutPromise
189+
]);
190+
} catch {
191+
console.warn('Twin loading timed out, showing parts without twin status');
192+
twins = [];
193+
}
166194
}
167195

168196
// Get relevant twins for current parts (call directly, don't use the callback)
@@ -200,6 +228,7 @@ const SerializedPartsTable = ({ parts, onRefresh }: SerializedPartsTableProps) =
200228
}));
201229
setRows(rowsWithoutStatus);
202230
} finally {
231+
// ALWAYS clear loading state, even on timeout or error
203232
setIsInitialLoading(false);
204233
}
205234
};

ichub-frontend/src/features/serialized-parts/pages/SerializedParts.tsx

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,16 @@ const SerializedParts = () => {
4141
}
4242
setError(null);
4343

44-
const data = await fetchAllSerializedParts();
44+
// Add timeout to prevent infinite loading
45+
const timeoutPromise = new Promise<never>((_, reject) => {
46+
setTimeout(() => reject(new Error('Request timeout after 30 seconds')), 30000);
47+
});
48+
49+
const data = await Promise.race([
50+
fetchAllSerializedParts(),
51+
timeoutPromise
52+
]);
53+
4554
setSerializedParts(data || []);
4655

4756
// If we got empty data, show a warning but don't treat it as an error
@@ -57,6 +66,7 @@ const SerializedParts = () => {
5766
);
5867
setSerializedParts([]); // Ensure we have an empty array
5968
} finally {
69+
// Always clear loading states, even on error
6070
setIsLoading(false);
6171
setIsRetrying(false);
6272
}

0 commit comments

Comments
 (0)