diff --git a/packages/twenty-server/src/engine/twenty-orm/factories/workspace-datasource.factory.ts b/packages/twenty-server/src/engine/twenty-orm/factories/workspace-datasource.factory.ts index 9a07903a4..1ed21b871 100644 --- a/packages/twenty-server/src/engine/twenty-orm/factories/workspace-datasource.factory.ts +++ b/packages/twenty-server/src/engine/twenty-orm/factories/workspace-datasource.factory.ts @@ -40,7 +40,7 @@ type CacheResult = { data: U; }; -const ONE_HOUR_IN_MS = 3600_000; +const TWENTY_MINUTES_IN_MS = 120_000; @Injectable() export class WorkspaceDatasourceFactory { @@ -58,6 +58,28 @@ export class WorkspaceDatasourceFactory { private readonly workspaceFeatureFlagsMapCacheService: WorkspaceFeatureFlagsMapCacheService, ) {} + private async conditionalDestroyDataSource( + dataSource: WorkspaceDataSource, + ): Promise { + const isPoolSharingEnabled = this.twentyConfigService.get( + 'PG_ENABLE_POOL_SHARING', + ); + + if (isPoolSharingEnabled) { + this.logger.debug( + `PromiseMemoizer Event: A WorkspaceDataSource (using shared pool) is being cleared. Actual pool closure managed by PgPoolSharedService. Not calling dataSource.destroy().`, + ); + // We should NOT call dataSource.destroy() here, because that would end + // the shared pool, potentially affecting other active users of that pool. + // The PgPoolSharedService is responsible for the lifecycle of shared pools. + } else { + this.logger.debug( + `PromiseMemoizer Event: A WorkspaceDataSource (using dedicated pool) is being cleared. Calling safelyDestroyDataSource.`, + ); + await this.safelyDestroyDataSource(dataSource); + } + } + private async safelyDestroyDataSource( dataSource: WorkspaceDataSource, ): Promise { @@ -208,7 +230,8 @@ export class WorkspaceDatasourceFactory { // https://node-postgres.com/apis/pool // TypeORM doesn't allow sharing connection pools between data sources // So we keep a small pool open for longer if connection pooling patch isn't enabled - idleTimeoutMillis: ONE_HOUR_IN_MS, + // TODO: Probably not needed anymore when connection pooling patch is enabled + idleTimeoutMillis: TWENTY_MINUTES_IN_MS, max: 4, allowExitOnIdle: true, }, @@ -223,9 +246,7 @@ export class WorkspaceDatasourceFactory { return workspaceDataSource; }, - async (dataSource) => { - await this.safelyDestroyDataSource(dataSource); - }, + this.conditionalDestroyDataSource.bind(this), ); if (!workspaceDataSource) { @@ -377,9 +398,7 @@ export class WorkspaceDatasourceFactory { try { await this.promiseMemoizer.clearKeys( `${workspaceId}-`, - async (dataSource) => { - await this.safelyDestroyDataSource(dataSource); - }, + this.conditionalDestroyDataSource.bind(this), ); } catch (error) { // Log and swallow any errors during cleanup to prevent crashes diff --git a/packages/twenty-server/src/engine/twenty-orm/pg-shared-pool/pg-shared-pool.service.ts b/packages/twenty-server/src/engine/twenty-orm/pg-shared-pool/pg-shared-pool.service.ts index 1c303d88c..4c53afbad 100644 --- a/packages/twenty-server/src/engine/twenty-orm/pg-shared-pool/pg-shared-pool.service.ts +++ b/packages/twenty-server/src/engine/twenty-orm/pg-shared-pool/pg-shared-pool.service.ts @@ -20,11 +20,7 @@ interface PoolWithEndTracker extends Pool { } interface ExtendedPoolConfig extends PoolConfig { - extra?: { - allowExitOnIdle?: boolean; - idleTimeoutMillis?: number; - [key: string]: unknown; - }; + allowExitOnIdle?: boolean; } interface PoolInternalStats { @@ -367,10 +363,9 @@ export class PgPoolSharedService { poolConfig.idleTimeoutMillis = idleTimeoutMs; } - if (!poolConfig.extra) { - poolConfig.extra = {}; + if (allowExitOnIdle) { + poolConfig.allowExitOnIdle = allowExitOnIdle; } - poolConfig.extra.allowExitOnIdle = allowExitOnIdle; const key = buildPoolKey(poolConfig); const existing = poolsMap.get(key);