DEV: Bump uppy module versions for retryable prepareUploadParts (#14629)

DEV: Bump uppy module versions for retryable prepareUploadParts (#14629)

This commit bumps the following uppy modules:

  • @uppy/aws-s3
  • @uppy/aws-s3-multipart
  • @uppy/core
  • @uppy/drop-target
  • @uppy/xhr-upload

This is done so we can use the new functionality for retrying failed prepareUploadParts calls, introduced in Retry `prepareUploadParts` on fail for `@uppy/aws-s3-multipart` (#3224) · transloadit/uppy@e435f4a · GitHub.

I also needed to make some changes to composer-upload-uppy to support this retrying, while at the same time being able to throw a bootbox with the error message if the number of retries are exceeded.

diff --git a/app/assets/javascripts/discourse/app/mixins/composer-upload-uppy.js b/app/assets/javascripts/discourse/app/mixins/composer-upload-uppy.js
index 78b0618..3089a39 100644
--- a/app/assets/javascripts/discourse/app/mixins/composer-upload-uppy.js
+++ b/app/assets/javascripts/discourse/app/mixins/composer-upload-uppy.js
@@ -1,4 +1,5 @@
 import Mixin from "@ember/object/mixin";
+import { Promise } from "rsvp";
 import ExtendableUploader from "discourse/mixins/extendable-uploader";
 import { ajax } from "discourse/lib/ajax";
 import { deepMerge } from "discourse-common/lib/object";
@@ -374,6 +375,7 @@ export default Mixin.create(ExtendableUploader, {
 
   _useS3MultipartUploads() {
     const self = this;
+    const retryDelays = [0, 1000, 3000, 5000];
 
     this._uppyInstance.use(AwsS3Multipart, {
       // controls how many simultaneous _chunks_ are uploaded, not files,
@@ -384,6 +386,7 @@ export default Mixin.create(ExtendableUploader, {
       // chunk size via getChunkSize(file), so we may want to increase
       // the chunk size for larger files
       limit: 10,
+      retryDelays,
 
       createMultipartUpload(file) {
         self._uppyInstance.emit("create-multipart", file.id);
@@ -419,22 +422,53 @@ export default Mixin.create(ExtendableUploader, {
       },
 
       prepareUploadParts(file, partData) {
-        return (
-          ajax("/uploads/batch-presign-multipart-parts.json", {
-            type: "POST",
-            data: {
-              part_numbers: partData.partNumbers,
-              unique_identifier: file.meta.unique_identifier,
-            },
+        if (file.preparePartsRetryAttempts === undefined) {
+          file.preparePartsRetryAttempts = 0;
+        }
+        return ajax("/uploads/batch-presign-multipart-parts.json", {
+          type: "POST",
+          data: {
+            part_numbers: partData.partNumbers,
+            unique_identifier: file.meta.unique_identifier,
+          },
+        })
+          .then((data) => {
+            if (file.preparePartsRetryAttempts) {
+              delete file.preparePartsRetryAttempts;
+              self._consoleDebug(
+                `[uppy] Retrying batch fetch for ${file.id} was successful, continuing.`
+              );
+            }
+            return { presignedUrls: data.presigned_urls };
           })
-            .then((data) => {
-              return { presignedUrls: data.presigned_urls };
-            })
-            // uppy is inconsistent, an error here does not fire the upload-error event
-            .catch((err) => {
+          .catch((err) => {
+            const status = err.jqXHR.status;
+
+            // it is kind of ugly to have to track the retry attempts for
+            // the file based on the retry delays, but uppy's `retryable`
+            // function expects the rejected Promise data to be structured
+            // _just so_, and provides no interface for us to tell how many
+            // times the upload has been retried (which it tracks internally)
+            //
+            // if we exceed the attempts then there is no way that uppy will
+            // retry the upload once again, so in that case the alert can
+            // be safely shown to the user that their upload has failed.
+            if (file.preparePartsRetryAttempts < retryDelays.length) {
+              file.preparePartsRetryAttempts += 1;
+              const attemptsLeft =
+                retryDelays.length - file.preparePartsRetryAttempts + 1;
+              self._consoleDebug(
+                `[uppy] Fetching a batch of upload part URLs for ${file.id} failed with status ${status}, retrying ${attemptsLeft} more times...`
+              );
+              return Promise.reject({ source: { status } });
+            } else {
+              self._consoleDebug(
+                `[uppy] Fetching a batch of upload part URLs for ${file.id} failed too many times, throwing error.`
+              );
+              // uppy is inconsistent, an error here does not fire the upload-error event
               self._handleUploadError(file, err);
-            })
-        );
+            }
+          });
       },
 
       completeMultipartUpload(file, data) {
diff --git a/app/assets/javascripts/discourse/package.json b/app/assets/javascripts/discourse/package.json
index b1c930f..0f3ee57 100644
--- a/app/assets/javascripts/discourse/package.json
+++ b/app/assets/javascripts/discourse/package.json
@@ -21,11 +21,11 @@
     "@ember/test-helpers": "^2.2.0",
     "@glimmer/component": "^1.0.0",
     "@popperjs/core": "2.9.3",
-    "@uppy/aws-s3": "^2.0.2",
-    "@uppy/aws-s3-multipart": "^2.0.2",
-    "@uppy/core": "^2.0.1",
-    "@uppy/drop-target": "^1.0.1",
-    "@uppy/xhr-upload": "^2.0.1",
+    "@uppy/aws-s3": "^2.0.4",
+    "@uppy/aws-s3-multipart": "^2.1.0",
+    "@uppy/core": "^2.1.0",
+    "@uppy/drop-target": "^1.1.0",
+    "@uppy/xhr-upload": "^2.0.4",
     "admin": "^1.0.0",
     "bent": "^7.3.12",
     "broccoli-asset-rev": "^3.0.0",
diff --git a/app/assets/javascripts/yarn.lock b/app/assets/javascripts/yarn.lock
index 72ebb0d..00dcf52 100644
--- a/app/assets/javascripts/yarn.lock
+++ b/app/assets/javascripts/yarn.lock
@@ -1387,81 +1387,72 @@
   resolved "https://registry.yarnpkg.com/@types/symlink-or-copy/-/symlink-or-copy-1.2.0.tgz#4151a81b4052c80bc2becbae09f3a9ec010a9c7a"
   integrity sha512-Lja2xYuuf2B3knEsga8ShbOdsfNOtzT73GyJmZyY7eGl2+ajOqrs8yM5ze0fsSoYwvA6bw7/Qr7OZ7PEEmYwWg==
 
-"@uppy/aws-s3-multipart@^2.0.2":
-  version "2.0.2"
-  resolved "https://registry.yarnpkg.com/@uppy/aws-s3-multipart/-/aws-s3-multipart-2.0.2.tgz#b12f0938fad61532f20a9aa1aa017a484d310c83"
-  integrity sha512-+PaYGP8/XbMnWAEEAcdh9AF1TzXXazHdHDJf+QEN2eH7UBEDpieY2P7c4t/yhZXY25ifOQjKryGt8inoAaHJDA==
+"@uppy/aws-s3-multipart@^2.1.0":
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/@uppy/aws-s3-multipart/-/aws-s3-multipart-2.1.1.tgz#7749491067ab72249dab201cc12409e57f2dbb1a"
+  integrity sha512-p+oFSCWEUc7ptv73sdZuWoq10hh0vzmP4cxwBEX/+nrplLFSuRUJ+z2XnNEigo8jXHWbA86k6tEX/3XIUsslgg==
   dependencies:
-    "@uppy/companion-client" "^2.0.0"
-    "@uppy/utils" "^4.0.0"
+    "@uppy/companion-client" "^2.0.3"
+    "@uppy/utils" "^4.0.3"
 
-"@uppy/aws-s3@^2.0.2":
-  version "2.0.2"
-  resolved "https://registry.yarnpkg.com/@uppy/aws-s3/-/aws-s3-2.0.2.tgz#6bd4e17bf3984bf7f8633264c3669a454d9853d5"
-  integrity sha512-Nxp0nFGTVYgNIVN4bHdWHx+1nEkdCdFeYGw3KltIGPhzN4RRMAvrsCB3Mk4AAWL4KSVKs4BgkNfYNVt3nRJVqg==
+"@uppy/aws-s3@^2.0.4":
+  version "2.0.5"
+  resolved "https://registry.yarnpkg.com/@uppy/aws-s3/-/aws-s3-2.0.5.tgz#dae2edb819b8e79119304a1659b931a862bf1e45"
+  integrity sha512-VWqVtmKtV/wSLCZdFbWlUt+CS7W/KZv20Pmm3JgcDLrQk3PdciYg3L9x65FTP8kSDsiXCwMg7uO5HfbspZWx9Q==
   dependencies:
-    "@uppy/companion-client" "^2.0.0"
-    "@uppy/utils" "^4.0.0"
-    "@uppy/xhr-upload" "^2.0.2"
+    "@uppy/companion-client" "^2.0.3"
+    "@uppy/utils" "^4.0.3"
+    "@uppy/xhr-upload" "^2.0.5"
     nanoid "^3.1.25"
 
-"@uppy/companion-client@^2.0.0":
-  version "2.0.0"
-  resolved "https://registry.yarnpkg.com/@uppy/companion-client/-/companion-client-2.0.0.tgz#60980d949d1ed15fe88bc8358171a938289b917c"
-  integrity sha512-TH/uw6aVeDKHcoepM9QAbSMMoi4MqUEG+loOEDwkB0CPkJGRYLqwvpnaO9pnELE7k1ZHfGGvRw0lxbkq5olGAg==
+"@uppy/companion-client@^2.0.3":
+  version "2.0.3"
+  resolved "https://registry.yarnpkg.com/@uppy/companion-client/-/companion-client-2.0.3.tgz#d3cd30ebbc9f87d27374d13258b5d304366f10d5"
+  integrity sha512-I1baKKBpb3d//q3agRtNV3UD/sA7EecFOfoVSpMlPkFu6oQqxjSC5OFXTf3fa8X+wo4Lcutv1++3igPJ1zrgbA==
   dependencies:
-    "@uppy/utils" "^4.0.0"
+    "@uppy/utils" "^4.0.3"
     namespace-emitter "^2.0.1"
 
-"@uppy/core@^2.0.1":
-  version "2.0.1"
-  resolved "https://registry.yarnpkg.com/@uppy/core/-/core-2.0.1.tgz#e9686ce3e5560593d249c455a9b3c542509e2289"
-  integrity sha512-MdSvc3ngVebfSBHYLKzFFSUxAatSqH/vYP6v4R3uU/zFaZ0cW9A/Xm52S6rGLKf1d5ZNOvZjesdkre6d61m2Eg==
+"@uppy/core@^2.1.0":

[... diff too long, it was truncated ...]

GitHub sha: ca7fd77a94c880085bfdae41bd9efca4b2db1c03

This commit appears in #14629 which was approved by tgxworld. It was merged by martin.