Skip to content

Commit 9f2d8e1

Browse files
committed
fix: add error handling for share queries and filter fetch retries
- Gracefully handle getUserShares failures by returning empty result - Add retry logic with cooldown to prevent infinite filter fetch loops - Add remotion build output to gitignore
1 parent d35d646 commit 9f2d8e1

3 files changed

Lines changed: 70 additions & 10 deletions

File tree

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,3 +141,6 @@ services/comfyui/
141141

142142
# Windows Zone.Identifier metadata files
143143
*:Zone.Identifier
144+
145+
# Remotion build output
146+
apps/api/services/remotion/out/

apps/api/routes/share/shareController.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -621,7 +621,18 @@ router.get(
621621
});
622622
}
623623

624-
const allShares = await service.getUserShares(userId, 'image');
624+
let allShares;
625+
try {
626+
allShares = await service.getUserShares(userId, 'image');
627+
} catch (queryError) {
628+
log.warn('Failed to query user shares, returning empty result:', queryError);
629+
return res.json({
630+
success: true,
631+
shares: [],
632+
count: 0,
633+
limit,
634+
});
635+
}
625636
const recentShares = allShares.slice(0, limit);
626637

627638
res.json({

apps/web/src/features/notebook/stores/notebookStore.ts

Lines changed: 55 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,14 @@ export type ActiveFilters = Record<
2525
Record<string, string[] | { date_from: string | null; date_to: string | null }>
2626
>;
2727

28+
interface FilterFetchError {
29+
timestamp: number;
30+
retryCount: number;
31+
}
32+
33+
const FILTER_FETCH_MAX_RETRIES = 3;
34+
const FILTER_FETCH_RETRY_COOLDOWN_MS = 30_000; // 30 seconds before allowing retry
35+
2836
interface NotebookState {
2937
qaCollections: NotebookCollection[];
3038
loading: boolean;
@@ -35,6 +43,7 @@ interface NotebookState {
3543
filterValuesCache: FilterValuesCache; // { [collectionId]: { [field]: { label, values } } }
3644
activeFilters: ActiveFilters; // { [collectionId]: { [field]: [value1, value2, ...] } }
3745
loadingFilters: Record<string, boolean>; // { [collectionId]: boolean }
46+
filterFetchErrors: Record<string, FilterFetchError>; // { [collectionId]: { timestamp, retryCount } }
3847

3948
// Actions
4049
setLoading: (loading: boolean) => void;
@@ -102,6 +111,7 @@ const useNotebookStore = create<NotebookState>((set, get) => ({
102111
filterValuesCache: {},
103112
activeFilters: {},
104113
loadingFilters: {},
114+
filterFetchErrors: {},
105115

106116
// Actions
107117
setLoading: (loading) => set({ loading }),
@@ -203,7 +213,10 @@ const useNotebookStore = create<NotebookState>((set, get) => ({
203213
requestData.document_ids = collectionData.documents || [];
204214
}
205215

206-
const response = await apiClient.put(`/auth/notebook-collections/${collectionId}`, requestData);
216+
const response = await apiClient.put(
217+
`/auth/notebook-collections/${collectionId}`,
218+
requestData
219+
);
207220

208221
const data = response.data;
209222

@@ -333,12 +346,27 @@ const useNotebookStore = create<NotebookState>((set, get) => ({
333346
// ─── Filter Actions ────────────────────────────────────────────────────
334347

335348
fetchFilterValues: async (collectionId) => {
336-
const { filterValuesCache, loadingFilters } = get();
349+
const { filterValuesCache, loadingFilters, filterFetchErrors } = get();
337350

351+
// Already cached or currently loading - return cached value
338352
if (filterValuesCache[collectionId] || loadingFilters[collectionId]) {
339353
return filterValuesCache[collectionId];
340354
}
341355

356+
// Check if we previously failed and should not retry yet
357+
const previousError = filterFetchErrors[collectionId];
358+
if (previousError) {
359+
const { retryCount, timestamp } = previousError;
360+
// If max retries exceeded, do not retry
361+
if (retryCount >= FILTER_FETCH_MAX_RETRIES) {
362+
return null;
363+
}
364+
// If cooldown has not elapsed, do not retry
365+
if (Date.now() - timestamp < FILTER_FETCH_RETRY_COOLDOWN_MS) {
366+
return null;
367+
}
368+
}
369+
342370
set((state) => ({
343371
loadingFilters: { ...state.loadingFilters, [collectionId]: true },
344372
}));
@@ -348,17 +376,34 @@ const useNotebookStore = create<NotebookState>((set, get) => ({
348376
const data = response.data;
349377

350378
if (data.filters) {
351-
set((state) => ({
352-
filterValuesCache: {
353-
...state.filterValuesCache,
354-
[collectionId]: data.filters,
355-
},
356-
loadingFilters: { ...state.loadingFilters, [collectionId]: false },
357-
}));
379+
set((state) => {
380+
// Clear any previous error on success
381+
const { [collectionId]: _removed, ...remainingErrors } = state.filterFetchErrors;
382+
return {
383+
filterValuesCache: {
384+
...state.filterValuesCache,
385+
[collectionId]: data.filters,
386+
},
387+
loadingFilters: { ...state.loadingFilters, [collectionId]: false },
388+
filterFetchErrors: remainingErrors,
389+
};
390+
});
358391
return data.filters;
359392
}
360393
} catch (error) {
361394
console.error('[notebookStore] Error fetching filters:', collectionId, error);
395+
// Record the error to prevent infinite retries
396+
set((state) => ({
397+
loadingFilters: { ...state.loadingFilters, [collectionId]: false },
398+
filterFetchErrors: {
399+
...state.filterFetchErrors,
400+
[collectionId]: {
401+
timestamp: Date.now(),
402+
retryCount: (state.filterFetchErrors[collectionId]?.retryCount ?? 0) + 1,
403+
},
404+
},
405+
}));
406+
return null;
362407
}
363408

364409
set((state) => ({
@@ -525,6 +570,7 @@ const useNotebookStore = create<NotebookState>((set, get) => ({
525570
filterValuesCache: {},
526571
activeFilters: {},
527572
loadingFilters: {},
573+
filterFetchErrors: {},
528574
}),
529575
}));
530576

0 commit comments

Comments
 (0)