From 1e615f71029d6c7bb884df712f8fbd0ed3295ea9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix=20Malfait?= Date: Thu, 18 Dec 2025 08:26:07 +0100 Subject: [PATCH] fix: ensure QueryRunner is released in workspace schema operations (#16649) ## Summary Fixes a database connection leak in `WorkspaceDataSourceService` where `QueryRunner.release()` was not being called when schema operations failed. ## Problem The `createWorkspaceDBSchema` and `deleteWorkspaceDBSchema` methods use TypeORM's QueryRunner but didn't wrap the operations in try-catch-finally blocks. When schema operations fail (e.g., permission denied, schema conflicts), the `QueryRunner.release()` method was never called. **Impact:** Failed schema operations leak database connections, which can exhaust the connection pool and cause the application to hang or crash under load. ## Solution Wrap both methods in try-finally blocks to ensure `queryRunner.release()` is always called, regardless of whether the operation succeeds or fails. ## Changes - `createWorkspaceDBSchema`: Wrapped in try-finally to ensure connection release - `deleteWorkspaceDBSchema`: Wrapped in try-finally to ensure connection release --- .../workspace-datasource.service.ts | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/packages/twenty-server/src/engine/workspace-datasource/workspace-datasource.service.ts b/packages/twenty-server/src/engine/workspace-datasource/workspace-datasource.service.ts index a5526d9332..228dea0495 100644 --- a/packages/twenty-server/src/engine/workspace-datasource/workspace-datasource.service.ts +++ b/packages/twenty-server/src/engine/workspace-datasource/workspace-datasource.service.ts @@ -37,14 +37,15 @@ export class WorkspaceDataSourceService { */ public async createWorkspaceDBSchema(workspaceId: string): Promise { const schemaName = getWorkspaceSchemaName(workspaceId); - const queryRunner = this.coreDataSource.createQueryRunner(); - await queryRunner.createSchema(schemaName, true); + try { + await queryRunner.createSchema(schemaName, true); - await queryRunner.release(); - - return schemaName; + return schemaName; + } finally { + await queryRunner.release(); + } } /** @@ -56,12 +57,13 @@ export class WorkspaceDataSourceService { */ public async deleteWorkspaceDBSchema(workspaceId: string): Promise { const schemaName = getWorkspaceSchemaName(workspaceId); - const queryRunner = this.coreDataSource.createQueryRunner(); - await queryRunner.dropSchema(schemaName, true, true); - - await queryRunner.release(); + try { + await queryRunner.dropSchema(schemaName, true, true); + } finally { + await queryRunner.release(); + } } public async executeRawQuery(