diff --git a/packages/@uppy/aws-s3-multipart/src/index.js b/packages/@uppy/aws-s3-multipart/src/index.js index 7f4932a60c..06f1e87169 100644 --- a/packages/@uppy/aws-s3-multipart/src/index.js +++ b/packages/@uppy/aws-s3-multipart/src/index.js @@ -33,6 +33,8 @@ class HTTPCommunicationQueue { #listParts + #previousRetryDelay + #requests #retryDelayIterator @@ -86,13 +88,25 @@ class HTTPCommunicationQueue { } if (status === 403 && err.message === 'Request has expired') { if (!requests.isPaused) { - const next = this.#retryDelayIterator?.next() - if (next == null || next.done) { - return false + // We don't want to exhaust the retryDelayIterator as long as there are + // more than one request in parallel, to give slower connection a chance + // to catch up with the expiry set in Companion. + if (requests.limit === 1 || this.#previousRetryDelay == null) { + const next = this.#retryDelayIterator?.next() + if (next == null || next.done) { + return false + } + // If there are more than 1 request done in parallel, the RLQ limit is + // decreased and the failed request is requeued after waiting for a bit. + // If there is only one request in parallel, the limit can't be + // decreased, so we iterate over `retryDelayIterator` as we do for + // other failures. + // `#previousRetryDelay` caches the value so we can re-use it next time. + this.#previousRetryDelay = next.value } // No need to stop the other requests, we just want to lower the limit. requests.rateLimit(0) - await new Promise(resolve => setTimeout(resolve, next.value)) + await new Promise(resolve => setTimeout(resolve, this.#previousRetryDelay)) } } else if (status === 429) { // HTTP 429 Too Many Requests => to avoid the whole download to fail, pause all requests.