Skip to content

Commit 025ff17

Browse files
fix: uncaught promise during multi-part upload could cause process exit
1 parent 3c99a5c commit 025ff17

File tree

1 file changed

+20
-3
lines changed

1 file changed

+20
-3
lines changed

object-uploader.ts

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,10 @@ export class ObjectUploader extends WritableStream<Uint8Array_> {
3535
let nextPartNumber = 1;
3636
let uploadId: string;
3737
const etags: { part: number; etag: string }[] = [];
38-
const partsPromises: Promise<Response>[] = []; // If doing multi-part upload, this holds a promise for each part so we can upload them in parallel
38+
/** If an error occurs during multi-part uploads, we temporarily store it here. */
39+
let multiUploadError: Error | undefined;
40+
/** If doing multi-part upload, this holds a promise for each part so we can upload them in parallel */
41+
const partsPromises: Promise<Response | void>[] = [];
3942

4043
super({
4144
start() {}, // required
@@ -100,7 +103,17 @@ export class ObjectUploader extends WritableStream<Uint8Array_> {
100103
etags.push({ part: partNumber, etag });
101104
return response;
102105
});
103-
partsPromises.push(partPromise);
106+
// We can't `await partPromise` now, because that will cause the uploads to
107+
// happen in series instead of parallel. But we don't want to let the promise
108+
// throw an exception when we haven't awaited it, because that can cause the
109+
// process to crash. So use .catch() to watch for errors and store them in
110+
// `multiUploadError` if they occur.
111+
partsPromises.push(partPromise.catch((err) => {
112+
// An error occurred when uploading this one part:
113+
if (!multiUploadError) {
114+
multiUploadError = err;
115+
}
116+
}));
104117
} catch (err) {
105118
// Throwing an error will make future writes to this sink fail.
106119
throw err;
@@ -110,8 +123,12 @@ export class ObjectUploader extends WritableStream<Uint8Array_> {
110123
if (result) {
111124
// This was already completed, in a single upload. Nothing more to do.
112125
} else if (uploadId) {
113-
// Wait for all parts to finish uploading
126+
// Wait for all parts to finish uploading (or fail)
114127
await Promise.all(partsPromises);
128+
if (multiUploadError) {
129+
// One or more parts failed to upload:
130+
throw multiUploadError;
131+
}
115132
// Sort the etags (required)
116133
etags.sort((a, b) => a.part > b.part ? 1 : -1);
117134
// Complete the multi-part upload

0 commit comments

Comments
 (0)