@@ -42,35 +42,74 @@ export interface S3ClientOptions {
42
42
accessKey ?: string
43
43
secretKey ?: string
44
44
role ?: string
45
- httpAgent ?: InstrumentedAgent
46
45
requestTimeout ?: number
46
+ httpAgents ?: S3HttpAgents
47
+ }
48
+
49
+ interface S3HttpAgents {
50
+ api : InstrumentedAgent
51
+ upload : InstrumentedAgent
52
+ download : InstrumentedAgent
47
53
}
48
54
49
55
/**
50
56
* S3Backend
51
57
* Interacts with a s3-compatible file system with this S3Adapter
52
58
*/
53
- export class S3Backend implements StorageBackendAdapter {
54
- client : S3Client
55
- agent : InstrumentedAgent
59
+ export class S3Backend implements StorageBackendAdapter < S3Client > {
60
+ apiClient : S3Client
61
+ uploadClient : S3Client
62
+ downloadClient : S3Client
63
+
64
+ agents : {
65
+ api : InstrumentedAgent
66
+ upload : InstrumentedAgent
67
+ download : InstrumentedAgent
68
+ }
56
69
57
70
constructor ( options : S3ClientOptions ) {
58
- this . agent =
59
- options . httpAgent ??
60
- createAgent ( 's3_default' , {
71
+ this . agents = options . httpAgents ?? {
72
+ api : createAgent ( 's3_api' , {
61
73
maxSockets : storageS3MaxSockets ,
62
- } )
74
+ } ) ,
75
+ upload : createAgent ( 's3_upload' , {
76
+ maxSockets : storageS3MaxSockets ,
77
+ } ) ,
78
+ download : createAgent ( 's3_download' , {
79
+ maxSockets : storageS3MaxSockets ,
80
+ } ) ,
81
+ }
63
82
64
- if ( this . agent . httpsAgent && tracingEnabled ) {
65
- this . agent . monitor ( )
83
+ if ( this . agents && tracingEnabled ) {
84
+ Object . values ( this . agents ) . forEach ( ( agent ) => {
85
+ agent . monitor ( )
86
+ } )
66
87
}
67
88
68
89
// Default client for API operations
69
- this . client = this . createS3Client ( {
90
+ this . apiClient = this . createS3Client ( {
70
91
...options ,
71
- name : 's3_default ' ,
72
- httpAgent : this . agent ,
92
+ name : 's3_api ' ,
93
+ httpAgent : this . agents . api ,
73
94
} )
95
+
96
+ // Dedicated client for downloads
97
+ this . downloadClient = this . createS3Client ( {
98
+ ...options ,
99
+ name : 's3_download' ,
100
+ httpAgent : this . agents . download ,
101
+ } )
102
+
103
+ // Dedicated client for uploads
104
+ this . uploadClient = this . createS3Client ( {
105
+ ...options ,
106
+ name : 's3_upload' ,
107
+ httpAgent : this . agents . upload ,
108
+ } )
109
+ }
110
+
111
+ getClient ( ) {
112
+ return this . apiClient
74
113
}
75
114
76
115
/**
@@ -98,7 +137,7 @@ export class S3Backend implements StorageBackendAdapter {
98
137
input . IfModifiedSince = new Date ( headers . ifModifiedSince )
99
138
}
100
139
const command = new GetObjectCommand ( input )
101
- const data = await this . client . send ( command , {
140
+ const data = await this . downloadClient . send ( command , {
102
141
abortSignal : signal ,
103
142
} )
104
143
@@ -144,7 +183,7 @@ export class S3Backend implements StorageBackendAdapter {
144
183
const dataStream = tracingFeatures ?. upload ? monitorStream ( body ) : body
145
184
146
185
const upload = new Upload ( {
147
- client : this . client ,
186
+ client : this . uploadClient ,
148
187
params : {
149
188
Bucket : bucketName ,
150
189
Key : withOptionalVersion ( key , version ) ,
@@ -212,7 +251,7 @@ export class S3Backend implements StorageBackendAdapter {
212
251
Bucket : bucket ,
213
252
Key : withOptionalVersion ( key , version ) ,
214
253
} )
215
- await this . client . send ( command )
254
+ await this . apiClient . send ( command )
216
255
}
217
256
218
257
/**
@@ -251,7 +290,7 @@ export class S3Backend implements StorageBackendAdapter {
251
290
ContentType : metadata ?. mimetype ,
252
291
CacheControl : metadata ?. cacheControl ,
253
292
} )
254
- const data = await this . client . send ( command )
293
+ const data = await this . apiClient . send ( command )
255
294
return {
256
295
httpStatusCode : data . $metadata . httpStatusCode || 200 ,
257
296
eTag : data . CopyObjectResult ?. ETag || '' ,
@@ -280,7 +319,7 @@ export class S3Backend implements StorageBackendAdapter {
280
319
ContinuationToken : options ?. nextToken || undefined ,
281
320
StartAfter : options ?. startAfter ,
282
321
} )
283
- const data = await this . client . send ( command )
322
+ const data = await this . apiClient . send ( command )
284
323
const keys =
285
324
data . Contents ?. filter ( ( ele ) => {
286
325
if ( options ?. beforeDate ) {
@@ -327,7 +366,7 @@ export class S3Backend implements StorageBackendAdapter {
327
366
Objects : s3Prefixes ,
328
367
} ,
329
368
} )
330
- await this . client . send ( command )
369
+ await this . apiClient . send ( command )
331
370
} catch ( e ) {
332
371
throw StorageBackendError . fromError ( e )
333
372
}
@@ -349,7 +388,7 @@ export class S3Backend implements StorageBackendAdapter {
349
388
Bucket : bucket ,
350
389
Key : withOptionalVersion ( key , version ) ,
351
390
} )
352
- const data = await this . client . send ( command )
391
+ const data = await this . apiClient . send ( command )
353
392
return {
354
393
cacheControl : data . CacheControl || 'no-cache' ,
355
394
mimetype : data . ContentType || 'application/octet-stream' ,
@@ -380,7 +419,7 @@ export class S3Backend implements StorageBackendAdapter {
380
419
MaxParts : maxParts ,
381
420
} )
382
421
383
- const result = await this . client . send ( command )
422
+ const result = await this . apiClient . send ( command )
384
423
385
424
return {
386
425
parts : result . Parts || [ ] ,
@@ -406,7 +445,7 @@ export class S3Backend implements StorageBackendAdapter {
406
445
}
407
446
408
447
const command = new GetObjectCommand ( input )
409
- return getSignedUrl ( this . client , command , { expiresIn : 600 } )
448
+ return getSignedUrl ( this . apiClient , command , { expiresIn : 600 } )
410
449
}
411
450
412
451
async createMultiPartUpload (
@@ -428,7 +467,7 @@ export class S3Backend implements StorageBackendAdapter {
428
467
} ,
429
468
} )
430
469
431
- const resp = await this . client . send ( createMultiPart )
470
+ const resp = await this . apiClient . send ( createMultiPart )
432
471
433
472
if ( ! resp . UploadId ) {
434
473
throw ERRORS . InvalidUploadId ( )
@@ -457,7 +496,7 @@ export class S3Backend implements StorageBackendAdapter {
457
496
ContentLength : length ,
458
497
} )
459
498
460
- const resp = await this . client . send ( paralellUploadS3 , {
499
+ const resp = await this . uploadClient . send ( paralellUploadS3 , {
461
500
abortSignal : signal ,
462
501
} )
463
502
@@ -491,7 +530,7 @@ export class S3Backend implements StorageBackendAdapter {
491
530
UploadId : uploadId ,
492
531
} )
493
532
494
- const partsResponse = await this . client . send ( listPartsInput )
533
+ const partsResponse = await this . apiClient . send ( listPartsInput )
495
534
parts = partsResponse . Parts || [ ]
496
535
}
497
536
@@ -507,7 +546,7 @@ export class S3Backend implements StorageBackendAdapter {
507
546
} ,
508
547
} )
509
548
510
- const response = await this . client . send ( completeUpload )
549
+ const response = await this . apiClient . send ( completeUpload )
511
550
512
551
let location = key
513
552
let bucket = bucketName
@@ -534,7 +573,7 @@ export class S3Backend implements StorageBackendAdapter {
534
573
Key : key ,
535
574
UploadId : uploadId ,
536
575
} )
537
- await this . client . send ( abortUpload )
576
+ await this . apiClient . send ( abortUpload )
538
577
}
539
578
540
579
async uploadPartCopy (
@@ -556,7 +595,7 @@ export class S3Backend implements StorageBackendAdapter {
556
595
CopySourceRange : bytesRange ? `bytes=${ bytesRange . fromByte } -${ bytesRange . toByte } ` : undefined ,
557
596
} )
558
597
559
- const part = await this . client . send ( uploadPartCopy )
598
+ const part = await this . uploadClient . send ( uploadPartCopy )
560
599
561
600
return {
562
601
eTag : part . CopyPartResult ?. ETag ,
@@ -565,14 +604,18 @@ export class S3Backend implements StorageBackendAdapter {
565
604
}
566
605
567
606
async backup ( backupInfo : BackupObjectInfo ) {
568
- return new ObjectBackup ( this . client , backupInfo ) . backup ( )
607
+ return new ObjectBackup ( this . apiClient , backupInfo ) . backup ( )
569
608
}
570
609
571
610
close ( ) {
572
- this . agent . close ( )
611
+ Object . values ( this . agents ) . forEach ( ( agent ) => {
612
+ agent . close ( )
613
+ } )
573
614
}
574
615
575
- protected createS3Client ( options : S3ClientOptions & { name : string } ) {
616
+ protected createS3Client (
617
+ options : S3ClientOptions & { name : string ; httpAgent : InstrumentedAgent }
618
+ ) {
576
619
const params : S3ClientConfig = {
577
620
region : options . region ,
578
621
runtime : 'node' ,
0 commit comments