From 22f7fd25ffd0aae33e66eadf7e233b6fd33a79e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A6=D0=B2=D1=8B=D0=BB=D0=B5=D0=B2=20=D0=90=D0=BB=D0=B5?= =?UTF-8?q?=D0=BA=D1=81=D0=B0=D0=BD=D0=B4=D1=80=20=D0=92=D0=B0=D0=B4=D0=B8?= =?UTF-8?q?=D0=BC=D0=BE=D0=B2=D0=B8=D1=87?= Date: Wed, 29 Jul 2026 10:53:49 +0300 Subject: [PATCH] perf(metadata): bound bulk re-enrich concurrency A large batch selection fired hundreds of simultaneous requests (each also enqueuing a worker job). Run them in batches of BULK_CONCURRENCY. Co-Authored-By: Claude Opus 4.8 --- .../metadata-editor/MetadataEditorPage.tsx | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/src/features/metadata-editor/MetadataEditorPage.tsx b/src/features/metadata-editor/MetadataEditorPage.tsx index 8115b8d..312940c 100644 --- a/src/features/metadata-editor/MetadataEditorPage.tsx +++ b/src/features/metadata-editor/MetadataEditorPage.tsx @@ -65,6 +65,23 @@ function fieldStyle(): React.CSSProperties { return { width: '100%' }; } +// Cap how many bulk metadata ops run at once — a large selection would otherwise +// fire hundreds of simultaneous requests (each also spins up a worker enqueue). +const BULK_CONCURRENCY = 6; + +async function settleInBatches( + items: T[], + limit: number, + op: (item: T) => Promise, +): Promise[]> { + const results: PromiseSettledResult[] = []; + for (let i = 0; i < items.length; i += limit) { + const batch = items.slice(i, i + limit); + results.push(...(await Promise.allSettled(batch.map(op)))); + } + return results; +} + /** * `/tracks/:trackId/metadata` — A7 metadata editor: manual edits + AcoustID * match picker with a current-vs-proposed diff. `/metadata/batch` operates on a @@ -723,7 +740,7 @@ function BatchEditor() { setBusy(true); setResult(null); const ids = [...selected]; - const outcomes = await Promise.allSettled(ids.map(op)); + const outcomes = await settleInBatches(ids, BULK_CONCURRENCY, op); const ok = outcomes.filter((o) => o.status === 'fulfilled').length; setResult({ ok, fail: ids.length - ok }); setBusy(false);