@@ -122,74 +122,71 @@ export class ArtifactStorageReader {
122
122
} ,
123
123
} )
124
124
. catch ( err => {
125
- if ( this . s3Mirror ) {
126
- // Use two AbortSignals to avoid a situation
127
- // where Response.body is consumed,
128
- // but the request was aborted after being resolved.
129
- // When a fetch call is resolved successfully,
130
- // but a shared AbortSignal.cancel() is called for two fetches,
131
- // it causes an exception (can't read a response from an aborted requests)
132
- // when Response.body is consumed.
133
- const primaryController = new AbortController ( ) ;
134
- const mirrorController = new AbortController ( ) ;
135
-
136
- function abortOtherRequest ( ctrl : AbortController ) {
137
- return ( res : Response ) => {
138
- // abort other pending request
139
- const error = new Error ( 'Another request won the race.' ) ;
140
- // change the name so we have some metrics for this on our analytics dashboard
141
- error . name = 'AbortError' ;
142
- ctrl . abort ( error ) ;
143
-
144
- return res ;
145
- } ;
146
- }
147
-
148
- // Wait for the first successful response
149
- // or reject if both requests fail
150
- return Promise . any ( [
151
- this . s3 . client
152
- . fetch ( [ this . s3 . endpoint , this . s3 . bucketName , args . key ] . join ( '/' ) , {
153
- method : args . method ,
154
- headers : args . headers ,
155
- aws : {
156
- signQuery : true ,
157
- } ,
158
- timeout : this . timeout ,
159
- signal : primaryController . signal ,
160
- isResponseOk : response =>
161
- response . status === 200 || response . status === 304 || response . status === 404 ,
162
- onAttempt : args1 => {
163
- args . onAttempt ( {
164
- ...args1 ,
165
- isMirror : false ,
166
- } ) ;
167
- } ,
168
- } )
169
- . then ( abortOtherRequest ( mirrorController ) ) ,
170
- this . s3Mirror . client
171
- . fetch ( [ this . s3Mirror . endpoint , this . s3Mirror . bucketName , args . key ] . join ( '/' ) , {
172
- method : args . method ,
173
- headers : args . headers ,
174
- aws : {
175
- signQuery : true ,
176
- } ,
177
- timeout : this . timeout ,
178
- signal : mirrorController . signal ,
179
- isResponseOk : response =>
180
- response . status === 200 || response . status === 304 || response . status === 404 ,
181
- onAttempt : args1 => {
182
- args . onAttempt ( {
183
- ...args1 ,
184
- isMirror : true ,
185
- } ) ;
186
- } ,
187
- } )
188
- . then ( abortOtherRequest ( primaryController ) ) ,
189
- ] ) ;
125
+ if ( ! this . s3Mirror ) {
126
+ return Promise . reject ( err ) ;
127
+ }
128
+ // Use two AbortSignals to avoid a situation
129
+ // where Response.body is consumed,
130
+ // but the request was aborted after being resolved.
131
+ // When a fetch call is resolved successfully,
132
+ // but a shared AbortSignal.cancel() is called for two fetches,
133
+ // it causes an exception (can't read a response from an aborted requests)
134
+ // when Response.body is consumed.
135
+ const primaryController = new AbortController ( ) ;
136
+ const mirrorController = new AbortController ( ) ;
137
+
138
+ function abortOtherRequest ( ctrl : AbortController ) {
139
+ return ( res : Response ) => {
140
+ // abort other pending request
141
+ const error = new PendingRequestAbortedError ( ) ;
142
+ ctrl . abort ( error ) ;
143
+
144
+ return res ;
145
+ } ;
190
146
}
191
147
192
- return Promise . reject ( err ) ;
148
+ // Wait for the first successful response
149
+ // or reject if both requests fail
150
+ return Promise . any ( [
151
+ this . s3 . client
152
+ . fetch ( [ this . s3 . endpoint , this . s3 . bucketName , args . key ] . join ( '/' ) , {
153
+ method : args . method ,
154
+ headers : args . headers ,
155
+ aws : {
156
+ signQuery : true ,
157
+ } ,
158
+ timeout : this . timeout ,
159
+ signal : primaryController . signal ,
160
+ isResponseOk : response =>
161
+ response . status === 200 || response . status === 304 || response . status === 404 ,
162
+ onAttempt : args1 => {
163
+ args . onAttempt ( {
164
+ ...args1 ,
165
+ isMirror : false ,
166
+ } ) ;
167
+ } ,
168
+ } )
169
+ . then ( abortOtherRequest ( mirrorController ) ) ,
170
+ this . s3Mirror . client
171
+ . fetch ( [ this . s3Mirror . endpoint , this . s3Mirror . bucketName , args . key ] . join ( '/' ) , {
172
+ method : args . method ,
173
+ headers : args . headers ,
174
+ aws : {
175
+ signQuery : true ,
176
+ } ,
177
+ timeout : this . timeout ,
178
+ signal : mirrorController . signal ,
179
+ isResponseOk : response =>
180
+ response . status === 200 || response . status === 304 || response . status === 404 ,
181
+ onAttempt : args1 => {
182
+ args . onAttempt ( {
183
+ ...args1 ,
184
+ isMirror : true ,
185
+ } ) ;
186
+ } ,
187
+ } )
188
+ . then ( abortOtherRequest ( primaryController ) ) ,
189
+ ] ) ;
193
190
} ) ;
194
191
}
195
192
@@ -380,3 +377,10 @@ export class ArtifactStorageReader {
380
377
return response ;
381
378
}
382
379
}
380
+
381
+ class PendingRequestAbortedError extends Error {
382
+ constructor ( ) {
383
+ super ( 'Pending request was aborted' ) ;
384
+ this . name = 'PendingRequestAbortedError' ;
385
+ }
386
+ }
0 commit comments