From c7e884fdeca74b57b31cccd89f755c1c3536281c Mon Sep 17 00:00:00 2001 From: Administrator Date: Sun, 21 Jun 2026 03:44:37 +0200 Subject: [PATCH] perf(upload-manager): throttle progress emits on rotation/suspect paths MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The rotation-retry and suspect-alternate progressCb callbacks called _emitProgress (a synchronous EventEmitter emit plus a fresh object spread) on every stream chunk — hundreds per second per job — because they lacked the 250 ms lastEmitTime gate the primary upload path already has. With many concurrent uploads in rotation or suspect mode that is real main-thread emit amplification. Mirror the primary path's gate exactly: the activeEntry speed/bytes mutation stays ungated so the stats timer and speed monitor keep seeing fresh values; only the _emitProgress call is throttled to ~4/sec. Behavior-preserving — identical progress data, fewer emits. Co-Authored-By: Claude Opus 4.8 (1M context) --- lib/upload-manager.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/lib/upload-manager.js b/lib/upload-manager.js index af52573..d067b77 100644 --- a/lib/upload-manager.js +++ b/lib/upload-manager.js @@ -941,6 +941,8 @@ class UploadManager extends EventEmitter { const activeEntry = { jobId, speedKbs: 0, bytesUploaded: 0 }; this.activeJobs.set(uploadId, activeEntry); + let lastEmitTime = 0; + const PROGRESS_EMIT_INTERVAL = 250; const progressCb = (bytesUploaded, bytesTotal) => { const now = Date.now(); const timeDelta = (now - lastSpeedTime) / 1000; @@ -951,6 +953,8 @@ class UploadManager extends EventEmitter { } activeEntry.speedKbs = currentSpeedKbs; activeEntry.bytesUploaded = bytesUploaded; + if (now - lastEmitTime < PROGRESS_EMIT_INTERVAL) return; + lastEmitTime = now; const elapsed = Math.round((now - jobStart) / 1000); const remaining = currentSpeedKbs > 0 ? Math.round((bytesTotal - bytesUploaded) / (currentSpeedKbs * 1024)) : 0; this._emitProgress(uploadId, fileName, task.hoster, { accountId: task.accountId, @@ -1072,6 +1076,8 @@ class UploadManager extends EventEmitter { let currentSpeedKbs = 0; const activeEntry = { jobId, speedKbs: 0, bytesUploaded: 0 }; this.activeJobs.set(uploadId, activeEntry); + let lastEmitTime = 0; + const PROGRESS_EMIT_INTERVAL = 250; const progressCb = (bytesUploaded, bytesTotal) => { const now = Date.now(); const timeDelta = (now - lastSpeedTime) / 1000; @@ -1082,6 +1088,8 @@ class UploadManager extends EventEmitter { } activeEntry.speedKbs = currentSpeedKbs; activeEntry.bytesUploaded = bytesUploaded; + if (now - lastEmitTime < PROGRESS_EMIT_INTERVAL) return; + lastEmitTime = now; const elapsed = Math.round((now - jobStart) / 1000); const remaining = currentSpeedKbs > 0 ? Math.round((bytesTotal - bytesUploaded) / (currentSpeedKbs * 1024)) : 0; this._emitProgress(uploadId, fileName, task.hoster, { accountId: task.accountId,