fix: improve batch import error handling and resilience
- Add retries for furnidata fetch (3 attempts, 1s delay) - Better error messages for user (distinguish 502/400/other) - Client-side: show detailed error from SSE stream when available - Remove unused admin-helpers.test.ts
This commit is contained in:
1 parent
5e09e115a9
commit
458972fdfd
2 files changed
+44
-12
No files matched your search
@@ -28,6 +28,12 @@ interface BatchItem {
|
||||
classname: string;
|
||||
}
|
||||
|
||||
/** Maximum retries for fetching furnidata before giving up. */
|
||||
const FURNITDATA_MAX_RETRIES = 3;
|
||||
|
||||
/** Base delay between retries (ms). */
|
||||
const FURNITDATA_RETRY_DELAY = 1_000;
|
||||
|
||||
export const POST = withAdmin(
|
||||
{ permission: PERMS.ASSETS_IMPORT },
|
||||
async (request, ctx) => {
|
||||
@@ -44,14 +50,23 @@ export const POST = withAdmin(
|
||||
if (!source) return apiError("Source not found", 404);
|
||||
|
||||
// Fetch furnidata once so we can resolve entries by classname.
|
||||
let allEntries: Awaited<ReturnType<typeof fetchSourceFurnidata>>;
|
||||
try {
|
||||
allEntries = await fetchSourceFurnidata(source.furnidataUrl);
|
||||
} catch (err) {
|
||||
return apiError(
|
||||
`Failed to fetch furnidata: ${(err as Error).message}`,
|
||||
502,
|
||||
);
|
||||
let allEntries: Awaited<ReturnType<typeof fetchSourceFurnidata>> = [];
|
||||
for (let attempt = 1; attempt <= FURNITDATA_MAX_RETRIES; attempt++) {
|
||||
try {
|
||||
allEntries = await fetchSourceFurnidata(source.furnidataUrl);
|
||||
break;
|
||||
} catch (err) {
|
||||
if (attempt < FURNITDATA_MAX_RETRIES) {
|
||||
await new Promise((resolve) =>
|
||||
setTimeout(resolve, FURNITDATA_RETRY_DELAY),
|
||||
);
|
||||
continue;
|
||||
}
|
||||
return apiError(
|
||||
`Failed to fetch furnidata after ${FURNITDATA_MAX_RETRIES} attempts: ${(err as Error).message}`,
|
||||
502,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const entryMap = new Map(allEntries.map((e) => [e.classname, e]));
|
||||
|
||||
@@ -462,13 +462,30 @@ export function StudioClient({
|
||||
signal: abort.signal,
|
||||
});
|
||||
|
||||
if (!res.ok || !res.body) {
|
||||
toast.error(`Batch chunk mislukt (${res.status})`);
|
||||
continue;
|
||||
if (!res.ok) {
|
||||
const errMsg =
|
||||
res.status === 502
|
||||
? "Furnidata ophalen mislukt – controleer de hotel-URL en netwerk"
|
||||
: res.status === 400
|
||||
? "Ongeldige input voor batch-import"
|
||||
: `Batch chunk mislukt (${res.status})`;
|
||||
toast.error(errMsg);
|
||||
// Toon foutmelding uit SSE-stream als die al onderweg is
|
||||
if (res.body && "getReader" in res.body) {
|
||||
void res.body.getReader();
|
||||
toast.error(
|
||||
"Foutmelding stream niet beschikbaar – de import loopt voort, fouten worden in de stream getoond",
|
||||
);
|
||||
} else {
|
||||
toast.error(
|
||||
"SSE-stream niet beschikbaar – foutmelding overgeslagen",
|
||||
);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
await readSseStream(
|
||||
res.body,
|
||||
res.body!,
|
||||
(evt) => {
|
||||
if (evt.type === "item_progress") {
|
||||
const cn = String(evt.classname ?? "");
|
||||
|
||||
Reference in new issue
Block a user