diff --git a/packages/core/src/env-set/create-pool.ts b/packages/core/src/env-set/create-pool.ts index 625b9dd12..a8e60283e 100644 --- a/packages/core/src/env-set/create-pool.ts +++ b/packages/core/src/env-set/create-pool.ts @@ -2,7 +2,7 @@ import { assert } from '@silverhand/essentials'; import { createMockPool, createMockQueryResult, createPool, parseDsn } from 'slonik'; import { createInterceptors } from 'slonik-interceptor-preset'; -const createPoolByEnv = async (databaseDsn: string, isTest: boolean) => { +const createPoolByEnv = async (databaseDsn: string, isTest: boolean, poolSize?: number) => { // Database connection is disabled in unit test environment if (isTest) { return createMockPool({ query: async () => createMockQueryResult([]) }); @@ -12,7 +12,7 @@ const createPoolByEnv = async (databaseDsn: string, isTest: boolean) => { assert(parseDsn(databaseDsn).databaseName, new Error('Database name is required')); - return createPool(databaseDsn, { interceptors }); + return createPool(databaseDsn, { interceptors, maximumPoolSize: poolSize }); }; export default createPoolByEnv; diff --git a/packages/core/src/env-set/index.ts b/packages/core/src/env-set/index.ts index 7d76b0c28..1bbe2d6c2 100644 --- a/packages/core/src/env-set/index.ts +++ b/packages/core/src/env-set/index.ts @@ -6,7 +6,7 @@ import type { DatabasePool } from 'slonik'; import { createLogtoConfigLibrary } from '#src/libraries/logto-config.js'; import { createLogtoConfigQueries } from '#src/queries/logto-config.js'; -import createPool from './create-pool.js'; +import createPoolByEnv from './create-pool.js'; import loadOidcValues from './oidc.js'; import { throwNotLoadedError } from './throw-errors.js'; import { getTenantEndpoint } from './utils.js'; @@ -37,7 +37,7 @@ export class EnvSet { return this.values.dbUrl; } - static sharedPool = createPool(this.dbUrl, this.isTest); + static sharedPool = createPoolByEnv(this.dbUrl, this.isTest, this.values.databasePoolSize); #pool: Optional; #oidc: Optional>>; @@ -61,7 +61,11 @@ export class EnvSet { } async load() { - const pool = await createPool(this.databaseUrl, EnvSet.isTest); + const pool = await createPoolByEnv( + this.databaseUrl, + EnvSet.isTest, + EnvSet.values.databasePoolSize + ); this.#pool = pool; diff --git a/packages/core/src/tenants/index.ts b/packages/core/src/tenants/index.ts index d79ece85f..af4cd2406 100644 --- a/packages/core/src/tenants/index.ts +++ b/packages/core/src/tenants/index.ts @@ -1,11 +1,13 @@ import LRUCache from 'lru-cache'; +import { EnvSet } from '#src/env-set/index.js'; + import Tenant from './Tenant.js'; export class TenantPool { protected cache = new LRUCache>({ - max: 100, - dispose: async (entry) => { + max: EnvSet.values.tenantPoolSize, + dispose: (tenant) => { const tenant = await entry; void tenant.dispose(); }, diff --git a/packages/shared/src/env/GlobalValues.ts b/packages/shared/src/env/GlobalValues.ts index c61429473..7abddb1ef 100644 --- a/packages/shared/src/env/GlobalValues.ts +++ b/packages/shared/src/env/GlobalValues.ts @@ -98,6 +98,11 @@ export default class GlobalValues { public readonly trustProxyHeader = yes(getEnv('TRUST_PROXY_HEADER')); public readonly ignoreConnectorVersionCheck = yes(getEnv('IGNORE_CONNECTOR_VERSION_CHECK')); + /** Maximum number of tenants to keep in the tenant pool. */ + public readonly tenantPoolSize = Number(getEnv('TENANT_POOL_SIZE', '100')); + /** Maximum number of clients to keep in a single database pool (i.e. per `Tenant` class). */ + public readonly databasePoolSize = Number(getEnv('DATABASE_POOL_SIZE', '20')); + public get dbUrl(): string { return this.databaseUrl; }