From 1aad09dba5b3608f8c2f85000827e98e59374c69 Mon Sep 17 00:00:00 2001 From: Anga205 Date: Fri, 24 Oct 2025 18:49:43 +0530 Subject: [PATCH] fix collection by stabilize upload queue > MAX_CONCURRENT_UPLOADS by debouncing pumpQueue --- .github/workflows/go.yml | 2 -- .github/workflows/web.yml | 2 -- frontend/src/pages/Collection.tsx | 47 ++++++++++++++++--------------- 3 files changed, 24 insertions(+), 27 deletions(-) diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index 4991e37..1c1227e 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -2,9 +2,7 @@ name: Compile Backend on: push: - branches: [ "main" ] pull_request: - branches: [ "main" ] jobs: build: diff --git a/.github/workflows/web.yml b/.github/workflows/web.yml index 14da474..2cfba29 100644 --- a/.github/workflows/web.yml +++ b/.github/workflows/web.yml @@ -2,9 +2,7 @@ name: Compile Frontend on: push: - branches: [ "main" ] pull_request: - branches: [ "main" ] jobs: build: diff --git a/frontend/src/pages/Collection.tsx b/frontend/src/pages/Collection.tsx index 17a07cd..479702f 100644 --- a/frontend/src/pages/Collection.tsx +++ b/frontend/src/pages/Collection.tsx @@ -32,9 +32,20 @@ const AddFilePopup: Component<{collectionId: string, isMobile?: boolean}> = (pro }; // Concurrency-aware scheduler state - let activeUploads = 0; + const [activeUploadsCount, setActiveUploadsCount] = createSignal(0); const MAX_CONCURRENT_UPLOADS = 3; + // Debounced queue pumping to avoid microtask storms when many files are pending + let pumpScheduled = false; + const requestPump = () => { + if (pumpScheduled) return; + pumpScheduled = true; + queueMicrotask(() => { + pumpScheduled = false; + pumpQueue(); + }); + }; + const waitWhilePaused = async () => { while (isPaused()) { await new Promise(r => setTimeout(r, 200)); @@ -67,7 +78,7 @@ const AddFilePopup: Component<{collectionId: string, isMobile?: boolean}> = (pro }); }); - activeUploads++; + setActiveUploadsCount(c => c + 1); try { await uploadFileInChunks( sf, @@ -95,8 +106,8 @@ const AddFilePopup: Component<{collectionId: string, isMobile?: boolean}> = (pro return ({ ...prev, [sf.uniqueId]: { ...prev[sf.uniqueId], status: 'error', errorMessage: error?.message || 'Upload failed' } }); }); } finally { - activeUploads--; - queueMicrotask(() => pumpQueue()); + setActiveUploadsCount(c => Math.max(0, c - 1)); + requestPump(); } }; @@ -104,31 +115,20 @@ const AddFilePopup: Component<{collectionId: string, isMobile?: boolean}> = (pro if (!open()) return; if (isPaused()) return; - // Ensure progress map entries exist - setUploadProgressMap(prev => { - const updated = { ...prev }; - selectedUploadFiles().forEach(sf => { - if (!updated[sf.uniqueId]) { - updated[sf.uniqueId] = { id: sf.uniqueId, name: sf.file.name, progress: 0, status: 'pending' }; - } - }); - return updated; - }); - const currentMap = uploadProgressMap(); - const available = Math.max(0, MAX_CONCURRENT_UPLOADS - activeUploads); + const available = Math.max(0, MAX_CONCURRENT_UPLOADS - activeUploadsCount()); if (available === 0) { setIsUploading(true); return; } const candidates = selectedUploadFiles().filter(sf => { - const st = currentMap[sf.uniqueId]?.status; + const st = currentMap[sf.uniqueId]?.status ?? 'pending'; return (st === 'pending' || st === 'error') && !cancelledFiles.has(sf.uniqueId); }).slice(0, available); if (candidates.length === 0) { - if (activeUploads === 0) setIsUploading(false); + if (activeUploadsCount() === 0) setIsUploading(false); return; } @@ -183,7 +183,7 @@ const AddFilePopup: Component<{collectionId: string, isMobile?: boolean}> = (pro }); return updatedMap; }); - if (!isPaused()) queueMicrotask(() => pumpQueue()); + if (!isPaused()) requestPump(); }; const handleFileChange = (event: Event) => { @@ -194,7 +194,7 @@ const AddFilePopup: Component<{collectionId: string, isMobile?: boolean}> = (pro if (input) input.value = ''; }; - const addDroppedFiles = (files: FileList | File[]) => { addFiles(files); if (open() && !isPaused()) queueMicrotask(() => pumpQueue()); }; + const addDroppedFiles = (files: FileList | File[]) => { addFiles(files); if (open() && !isPaused()) requestPump(); }; onMount(() => { const handler = (e: Event) => { @@ -241,7 +241,7 @@ const AddFilePopup: Component<{collectionId: string, isMobile?: boolean}> = (pro return status === 'pending' || status === 'error'; }).length; if (pendingCount > 0 && !isPaused()) { - queueMicrotask(() => pumpQueue()); + requestPump(); } } }); @@ -263,7 +263,7 @@ const AddFilePopup: Component<{collectionId: string, isMobile?: boolean}> = (pro })); } } else if (modifying() === "new") { - queueMicrotask(() => pumpQueue()); + requestPump(); } setSelectedExistingFiles([]); // Don't close automatically for uploads, let user see progress. @@ -296,6 +296,7 @@ const AddFilePopup: Component<{collectionId: string, isMobile?: boolean}> = (pro activeControllers.forEach(c => c.abort()); activeControllers.clear(); cancelledFiles.clear(); + pumpScheduled = false; } }}> @@ -383,7 +384,7 @@ const AddFilePopup: Component<{collectionId: string, isMobile?: boolean}> = (pro activeControllers.forEach(c => c.abort()); } else { // Resume: pump queue immediately - queueMicrotask(() => pumpQueue()); + requestPump(); } }} >