Skip to content

Commit 38f2e1f

Browse files
authored
fix(storage-*): update the client cache to use a map instead with cache keys per bucket config (#14267)
Fixes #14175 Updates the client caches to use a map with cache keys per bucket, this key is overridable using `cacheKey` but it defaults to `'adapter:bucketName'` string format eg. `'s3:primary-us'`. Currently because we use a single variable it means that if you were to instantiate the client multiple times in order to store different collections in different buckets it would all get sent to the last instantiated client as it would be overridden, this makes sure that it's correctly using the client instantiated per bucket.
1 parent 4de9088 commit 38f2e1f

File tree

4 files changed

+55
-19
lines changed

4 files changed

+55
-19
lines changed

packages/storage-azure/src/index.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,14 @@ export type AzureStorageOptions = {
3131
*/
3232
baseURL: string
3333

34+
/**
35+
* Optional cache key to identify the Azure Blob storage client instance.
36+
* If not provided, a default key will be used.
37+
*
38+
* @default `azure:containerName`
39+
*/
40+
clientCacheKey?: string
41+
3442
/**
3543
* Do uploads directly on the client to bypass limits on Vercel. You must allow CORS PUT method to your website.
3644
*/

packages/storage-azure/src/utils/getStorageClient.ts

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,23 @@ import { BlobServiceClient } from '@azure/storage-blob'
44

55
import type { AzureStorageOptions } from '../index.js'
66

7-
let storageClient: ContainerClient | null = null
7+
// Cache the Azure Blob storage clients in a map so that multiple instances are not overriding each other in the case of different configurations used per collection
8+
const azureClients = new Map<string, ContainerClient>()
89

910
export function getStorageClient(
10-
options: Pick<AzureStorageOptions, 'connectionString' | 'containerName'>,
11+
options: Pick<AzureStorageOptions, 'clientCacheKey' | 'connectionString' | 'containerName'>,
1112
): ContainerClient {
12-
if (storageClient) {
13-
return storageClient
13+
const cacheKey = options.clientCacheKey || `azure:${options.containerName}`
14+
15+
if (azureClients.has(cacheKey)) {
16+
return azureClients.get(cacheKey)!
1417
}
1518

1619
const { connectionString, containerName } = options
1720

1821
const blobServiceClient = BlobServiceClient.fromConnectionString(connectionString)
19-
storageClient = blobServiceClient.getContainerClient(containerName)
20-
return storageClient
22+
23+
azureClients.set(cacheKey, blobServiceClient.getContainerClient(containerName))
24+
25+
return azureClients.get(cacheKey)!
2126
}

packages/storage-gcs/src/index.ts

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,13 @@ export interface GcsStorageOptions {
2525
* The name of the bucket to use.
2626
*/
2727
bucket: string
28+
/**
29+
* Optional cache key to identify the GCS storage client instance.
30+
* If not provided, a default key will be used.
31+
*
32+
* @default `gcs:containerName`
33+
*/
34+
clientCacheKey?: string
2835
/**
2936
* Do uploads directly on the client to bypass limits on Vercel. You must allow CORS PUT method for the bucket to your website.
3037
*/
@@ -50,18 +57,20 @@ export interface GcsStorageOptions {
5057

5158
type GcsStoragePlugin = (gcsStorageArgs: GcsStorageOptions) => Plugin
5259

60+
const gcsClients = new Map<string, Storage>()
61+
5362
export const gcsStorage: GcsStoragePlugin =
5463
(gcsStorageOptions: GcsStorageOptions) =>
5564
(incomingConfig: Config): Config => {
56-
let storageClient: null | Storage = null
65+
const cacheKey = gcsStorageOptions.clientCacheKey || `gcs:${gcsStorageOptions.bucket}`
5766

5867
const getStorageClient = (): Storage => {
59-
if (storageClient) {
60-
return storageClient
68+
if (gcsClients.has(cacheKey)) {
69+
return gcsClients.get(cacheKey)!
6170
}
62-
storageClient = new Storage(gcsStorageOptions.options)
71+
gcsClients.set(cacheKey, new Storage(gcsStorageOptions.options))
6372

64-
return storageClient
73+
return gcsClients.get(cacheKey)!
6574
}
6675

6776
const adapter = gcsStorageInternal(getStorageClient, gcsStorageOptions)

packages/storage-s3/src/index.ts

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,14 @@ export type S3StorageOptions = {
3535

3636
bucket: string
3737

38+
/**
39+
* Optional cache key to identify the S3 storage client instance.
40+
* If not provided, a default key will be used.
41+
*
42+
* @default `s3:containerName`
43+
*/
44+
clientCacheKey?: string
45+
3846
/**
3947
* Do uploads directly on the client to bypass limits on Vercel. You must allow CORS PUT method for the bucket to your website.
4048
*/
@@ -79,7 +87,7 @@ export type S3StorageOptions = {
7987

8088
type S3StoragePlugin = (storageS3Args: S3StorageOptions) => Plugin
8189

82-
let storageClient: AWS.S3 | null = null
90+
const s3Clients = new Map<string, AWS.S3>()
8391

8492
const defaultRequestHandlerOpts: NodeHttpHandlerOptions = {
8593
httpAgent: {
@@ -95,16 +103,22 @@ const defaultRequestHandlerOpts: NodeHttpHandlerOptions = {
95103
export const s3Storage: S3StoragePlugin =
96104
(s3StorageOptions: S3StorageOptions) =>
97105
(incomingConfig: Config): Config => {
106+
const cacheKey = s3StorageOptions.clientCacheKey || `s3:${s3StorageOptions.bucket}`
107+
98108
const getStorageClient: () => AWS.S3 = () => {
99-
if (storageClient) {
100-
return storageClient
109+
if (s3Clients.has(cacheKey)) {
110+
return s3Clients.get(cacheKey)!
101111
}
102112

103-
storageClient = new AWS.S3({
104-
requestHandler: defaultRequestHandlerOpts,
105-
...(s3StorageOptions.config ?? {}),
106-
})
107-
return storageClient
113+
s3Clients.set(
114+
cacheKey,
115+
new AWS.S3({
116+
requestHandler: defaultRequestHandlerOpts,
117+
...(s3StorageOptions.config ?? {}),
118+
}),
119+
)
120+
121+
return s3Clients.get(cacheKey)!
108122
}
109123

110124
const isPluginDisabled = s3StorageOptions.enabled === false

0 commit comments

Comments
 (0)