From 1af7f8a94d22f427958f96cae053050c371d96c7 Mon Sep 17 00:00:00 2001 From: Administrator Date: Wed, 11 Mar 2026 03:56:04 +0100 Subject: [PATCH] fix: serialize interval waits so uploads stagger correctly Previously all jobs read the same lastStartTime simultaneously, causing them all to start at once. Now uses a per-hoster promise chain to ensure each job waits its turn. Co-Authored-By: Claude Opus 4.6 --- lib/upload-manager.js | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/lib/upload-manager.js b/lib/upload-manager.js index 7ac1481..34db135 100644 --- a/lib/upload-manager.js +++ b/lib/upload-manager.js @@ -35,6 +35,7 @@ class UploadManager extends EventEmitter { this.cancelledJobIds = new Set(); this.sessionBytes = 0; this.lastStartTime = {}; // hoster -> timestamp of last upload start + this.intervalLocks = {}; // hoster -> Promise chain for serialized interval waits this.globalThrottle = null; } @@ -544,14 +545,20 @@ class UploadManager extends EventEmitter { }); } - async _waitForInterval(hoster, intervalMs, signal) { - const now = Date.now(); - const last = this.lastStartTime[hoster] || 0; - const elapsed = now - last; - if (elapsed < intervalMs) { - await this._sleep(intervalMs - elapsed, signal); - } - this.lastStartTime[hoster] = Date.now(); + _waitForInterval(hoster, intervalMs, signal) { + // Serialize interval waits per hoster so concurrent jobs queue up properly + const prev = this.intervalLocks[hoster] || Promise.resolve(); + const next = prev.then(async () => { + const now = Date.now(); + const last = this.lastStartTime[hoster] || 0; + const elapsed = now - last; + if (elapsed < intervalMs) { + await this._sleep(intervalMs - elapsed, signal); + } + this.lastStartTime[hoster] = Date.now(); + }); + this.intervalLocks[hoster] = next.catch(() => {}); + return next; } cancelJobs(jobIds) {