From c8c6f1060a919b8a6aa409c7595fb276cd2de1e8 Mon Sep 17 00:00:00 2001 From: James Clifford Spratt Date: Sun, 28 Jun 2026 12:57:40 +0100 Subject: [PATCH] Bound per-source search time in All tab to keep it responsive --- src/core/search.ts | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/core/search.ts b/src/core/search.ts index 157dfc0..06d8fec 100644 --- a/src/core/search.ts +++ b/src/core/search.ts @@ -332,10 +332,19 @@ export async function searchAllSources( ); } - // Execute searches in parallel. Use allSettled so that one failing source - // (e.g. a network error or outage from a single API) doesn't wipe out the - // results from the others. - const settled = await Promise.allSettled(searchPromises); + // Give each source a time budget so a slow or unresponsive API (e.g. an + // Open Food Facts outage) can't hold up the results from the faster sources. + // Use allSettled so one failing source doesn't wipe out the others. + const SOURCE_TIMEOUT_MS = 8000; + const withTimeout = (p: Promise): Promise => + Promise.race([ + p, + new Promise((resolve) => { + window.setTimeout(() => resolve([]), SOURCE_TIMEOUT_MS); + }), + ]); + + const settled = await Promise.allSettled(searchPromises.map(withTimeout)); const results = settled .filter((r): r is PromiseFulfilledResult => r.status === 'fulfilled') .map((r) => r.value);