diff --git a/apps/api/v2/src/bootstrap.ts b/apps/api/v2/src/bootstrap.ts index a7bc78c9a2..22a2139804 100644 --- a/apps/api/v2/src/bootstrap.ts +++ b/apps/api/v2/src/bootstrap.ts @@ -1,6 +1,5 @@ import "./instrument"; -import process from "node:process"; import { API_VERSIONS, API_VERSIONS_ENUM, diff --git a/apps/api/v2/src/config/app.ts b/apps/api/v2/src/config/app.ts index a32a7d5854..4a951ee4fe 100644 --- a/apps/api/v2/src/config/app.ts +++ b/apps/api/v2/src/config/app.ts @@ -1,5 +1,4 @@ import { getEnv } from "@/env"; - import type { AppConfig } from "./type"; const loadConfig = (): AppConfig => { @@ -31,6 +30,7 @@ const loadConfig = (): AppConfig => { workerReadPoolMax: getEnv("DATABASE_READ_WORKER_POOL_MAX", 4), workerWritePoolMax: getEnv("DATABASE_WRITE_WORKER_POOL_MAX", 6), redisUrl: getEnv("REDIS_URL"), + usePool: getEnv("USE_POOL", "true") === "true", }, next: { authSecret: getEnv("NEXTAUTH_SECRET"), diff --git a/apps/api/v2/src/config/type.ts b/apps/api/v2/src/config/type.ts index 0b6cd7d0c0..f3ee7ebe6f 100644 --- a/apps/api/v2/src/config/type.ts +++ b/apps/api/v2/src/config/type.ts @@ -18,6 +18,7 @@ export type AppConfig = { workerReadPoolMax: number; workerWritePoolMax: number; redisUrl: string; + usePool: boolean; }; next: { authSecret: string; diff --git a/apps/api/v2/src/env.ts b/apps/api/v2/src/env.ts index c25a9cd480..5d6b8f27c2 100644 --- a/apps/api/v2/src/env.ts +++ b/apps/api/v2/src/env.ts @@ -40,11 +40,10 @@ export type Environment = { DATABASE_WRITE_WORKER_POOL_MAX: number; ENABLE_SLOTS_WORKERS: string; SLOTS_WORKER_POOL_SIZE: string; + USE_POOL: string; }; export const getEnv = (key: K, fallback?: Environment[K]): Environment[K] => { - // biome-ignore lint/style/noProcessEnv: - // biome-ignore lint/correctness/noProcessGlobal: const value = process.env[key] as Environment[K] | undefined; if (value === undefined) { diff --git a/apps/api/v2/src/main.ts b/apps/api/v2/src/main.ts index 144733438d..db8400facf 100644 --- a/apps/api/v2/src/main.ts +++ b/apps/api/v2/src/main.ts @@ -1,17 +1,13 @@ import "dotenv/config"; import { IncomingMessage, Server, ServerResponse } from "node:http"; -import process from "node:process"; import { Logger } from "@nestjs/common"; import { ConfigService } from "@nestjs/config"; import { NestFactory } from "@nestjs/core"; import type { NestExpressApplication } from "@nestjs/platform-express"; - import { WinstonModule } from "nest-winston"; import * as qs from "qs"; - import type { AppConfig } from "@/config/type"; - import { AppModule } from "./app.module"; import { bootstrap } from "./bootstrap"; import { loggerConfig } from "./lib/logger"; diff --git a/apps/api/v2/src/modules/prisma/prisma-read.service.ts b/apps/api/v2/src/modules/prisma/prisma-read.service.ts index 07722c5c89..ca28e9c049 100644 --- a/apps/api/v2/src/modules/prisma/prisma-read.service.ts +++ b/apps/api/v2/src/modules/prisma/prisma-read.service.ts @@ -1,63 +1,66 @@ -import type { OnModuleDestroy, OnModuleInit } from "@nestjs/common"; -import { Injectable, Logger } from "@nestjs/common"; +import { PrismaClient } from "@calcom/prisma/client"; +import { Injectable, Logger, type OnModuleDestroy, type OnModuleInit } from "@nestjs/common"; import { ConfigService } from "@nestjs/config"; import { PrismaPg } from "@prisma/adapter-pg"; import { Pool } from "pg"; -import { PrismaClient } from "@calcom/prisma/client"; - const DB_MAX_POOL_CONNECTION = 10; -export interface PrismaServiceOptions { - readUrl?: string; - maxReadConnections?: number; - e2e?: boolean; - type: "main" | "worker"; -} - @Injectable() export class PrismaReadService implements OnModuleInit, OnModuleDestroy { private logger = new Logger("PrismaReadService"); public prisma!: PrismaClient; private pool!: Pool; - private options!: PrismaServiceOptions; - constructor(private configService?: ConfigService) { + constructor(configService?: ConfigService) { if (configService) { // Use ConfigService defaults const readUrl = configService.get("db.readUrl", { infer: true }); const poolMax = parseInt( - configService.get("db.readPoolMax", { infer: true }) ?? DB_MAX_POOL_CONNECTION + configService.get("db.readPoolMax", { infer: true }) ?? DB_MAX_POOL_CONNECTION, + 10 ); const e2e = configService.get("e2e", { infer: true }) ?? false; + const usePool = configService.get("db.usePool", { infer: true }) ?? true; this.setOptions({ readUrl, maxReadConnections: poolMax, e2e, + usePool, type: "main", }); } } - setOptions(options: PrismaServiceOptions) { - this.options = options; - + setOptions(options: PrismaServiceOptions): void { const dbUrl = options.readUrl; const isE2E = options.e2e ?? false; + const usePool = options.usePool ?? true; - this.pool = new Pool({ - connectionString: dbUrl, - max: isE2E ? 1 : options.maxReadConnections ?? DB_MAX_POOL_CONNECTION, - idleTimeoutMillis: 300000, - }); + if (usePool) { + let maxReadConnections = options.maxReadConnections ?? DB_MAX_POOL_CONNECTION; + if (isE2E) { + maxReadConnections = 1; + } - const adapter = new PrismaPg(this.pool); - this.prisma = new PrismaClient({ adapter }); + this.pool = new Pool({ + connectionString: dbUrl, + max: maxReadConnections, + idleTimeoutMillis: 300000, + }); + + const adapter = new PrismaPg(this.pool); + this.prisma = new PrismaClient({ adapter }); + } else { + this.prisma = new PrismaClient({ + datasourceUrl: dbUrl, + }); + } } - async onModuleInit() { + async onModuleInit(): Promise { if (!this.prisma) return; try { @@ -68,7 +71,7 @@ export class PrismaReadService implements OnModuleInit, OnModuleDestroy { } } - async onModuleDestroy() { + async onModuleDestroy(): Promise { try { if (this.prisma) await this.prisma.$disconnect(); if (this.pool) await this.pool.end(); @@ -77,3 +80,11 @@ export class PrismaReadService implements OnModuleInit, OnModuleDestroy { } } } + +export interface PrismaServiceOptions { + readUrl?: string; + maxReadConnections?: number; + e2e?: boolean; + usePool?: boolean; + type: "main" | "worker"; +} diff --git a/apps/api/v2/src/modules/prisma/prisma-worker.module.ts b/apps/api/v2/src/modules/prisma/prisma-worker.module.ts index 4a84620e60..d4a04f05c4 100644 --- a/apps/api/v2/src/modules/prisma/prisma-worker.module.ts +++ b/apps/api/v2/src/modules/prisma/prisma-worker.module.ts @@ -1,7 +1,7 @@ -import { PrismaReadService } from "@/modules/prisma/prisma-read.service"; -import { PrismaWriteService } from "@/modules/prisma/prisma-write.service"; import { Module } from "@nestjs/common"; import { ConfigModule, ConfigService } from "@nestjs/config"; +import { PrismaReadService } from "@/modules/prisma/prisma-read.service"; +import { PrismaWriteService } from "@/modules/prisma/prisma-write.service"; @Module({ imports: [ConfigModule], @@ -12,7 +12,7 @@ import { ConfigModule, ConfigService } from "@nestjs/config"; const service = new PrismaReadService(); service.setOptions({ readUrl: config.get("db.readUrl", { infer: true }), - maxReadConnections: parseInt(config.get("db.workerReadPoolMax", { infer: true })), + maxReadConnections: parseInt(config.get("db.workerReadPoolMax", { infer: true }), 10), e2e: config.get("e2e", { infer: true }) ?? false, type: "worker", }); @@ -26,7 +26,7 @@ import { ConfigModule, ConfigService } from "@nestjs/config"; const service = new PrismaWriteService(); service.setOptions({ writeUrl: config.get("db.writeUrl", { infer: true }), - maxWriteConnections: parseInt(config.get("db.workerWritePoolMax", { infer: true })), + maxWriteConnections: parseInt(config.get("db.workerWritePoolMax", { infer: true }), 10), e2e: config.get("e2e", { infer: true }) ?? false, type: "worker", }); diff --git a/apps/api/v2/src/modules/prisma/prisma-write.service.ts b/apps/api/v2/src/modules/prisma/prisma-write.service.ts index cb60985f1e..c847b2d438 100644 --- a/apps/api/v2/src/modules/prisma/prisma-write.service.ts +++ b/apps/api/v2/src/modules/prisma/prisma-write.service.ts @@ -1,16 +1,16 @@ -import { OnModuleDestroy, OnModuleInit, Injectable, Logger } from "@nestjs/common"; +import { PrismaClient } from "@calcom/prisma/client"; +import { Injectable, Logger, OnModuleDestroy, OnModuleInit } from "@nestjs/common"; import { ConfigService } from "@nestjs/config"; import { PrismaPg } from "@prisma/adapter-pg"; import { Pool } from "pg"; -import { PrismaClient } from "@calcom/prisma/client"; - const DB_MAX_POOL_CONNECTION = 5; export interface PrismaServiceOptions { writeUrl?: string; maxWriteConnections?: number; e2e?: boolean; + usePool?: boolean; type: "main" | "worker"; } @@ -19,41 +19,54 @@ export class PrismaWriteService implements OnModuleInit, OnModuleDestroy { private logger = new Logger("PrismaWriteService"); public prisma!: PrismaClient; private pool!: Pool; - private options!: PrismaServiceOptions; - constructor(private configService?: ConfigService) { + constructor(configService?: ConfigService) { if (configService) { const writeUrl = configService.get("db.writeUrl", { infer: true }); const poolMax = parseInt( - configService.get("db.writePoolMax", { infer: true }) ?? DB_MAX_POOL_CONNECTION + String(configService.get("db.writePoolMax", { infer: true }) ?? DB_MAX_POOL_CONNECTION), + 10 ); const e2e = configService.get("e2e", { infer: true }) ?? false; + const usePool = configService.get("db.usePool", { infer: true }) ?? true; this.setOptions({ writeUrl, maxWriteConnections: poolMax, e2e, + usePool, type: "main", }); } } - setOptions(options: PrismaServiceOptions) { - this.options = options; - + setOptions(options: PrismaServiceOptions): void { const dbUrl = options.writeUrl; const isE2E = options.e2e ?? false; - this.pool = new Pool({ - connectionString: dbUrl, - max: isE2E ? 1 : options.maxWriteConnections ?? DB_MAX_POOL_CONNECTION, - idleTimeoutMillis: 300000, - }); + const usePool = options.usePool ?? true; - const adapter = new PrismaPg(this.pool); - this.prisma = new PrismaClient({ adapter }); + if (usePool) { + let maxWriteConnections = options.maxWriteConnections ?? DB_MAX_POOL_CONNECTION; + if (isE2E) { + maxWriteConnections = 1; + } + + this.pool = new Pool({ + connectionString: dbUrl, + max: maxWriteConnections, + idleTimeoutMillis: 300000, + }); + + const adapter = new PrismaPg(this.pool); + this.prisma = new PrismaClient({ adapter }); + } else { + this.prisma = new PrismaClient({ + datasourceUrl: dbUrl, + }); + } } - async onModuleInit() { + async onModuleInit(): Promise { if (!this.prisma) return; try { @@ -64,7 +77,7 @@ export class PrismaWriteService implements OnModuleInit, OnModuleDestroy { } } - async onModuleDestroy() { + async onModuleDestroy(): Promise { try { if (this.prisma) await this.prisma.$disconnect(); if (this.pool) await this.pool.end(); diff --git a/apps/api/v2/src/modules/prisma/prisma.module.ts b/apps/api/v2/src/modules/prisma/prisma.module.ts index 3c5d0d7565..4bb8ae53b3 100644 --- a/apps/api/v2/src/modules/prisma/prisma.module.ts +++ b/apps/api/v2/src/modules/prisma/prisma.module.ts @@ -1,7 +1,7 @@ -import { PrismaReadService } from "@/modules/prisma/prisma-read.service"; -import { PrismaWriteService } from "@/modules/prisma/prisma-write.service"; import { Module } from "@nestjs/common"; import { ConfigModule, ConfigService } from "@nestjs/config"; +import { PrismaReadService } from "@/modules/prisma/prisma-read.service"; +import { PrismaWriteService } from "@/modules/prisma/prisma-write.service"; @Module({ imports: [ConfigModule], @@ -12,7 +12,7 @@ import { ConfigModule, ConfigService } from "@nestjs/config"; const service = new PrismaReadService(); service.setOptions({ readUrl: config.get("db.readUrl", { infer: true }), - maxReadConnections: parseInt(config.get("db.readPoolMax", { infer: true })), + maxReadConnections: parseInt(config.get("db.readPoolMax", { infer: true }), 10), e2e: config.get("e2e", { infer: true }) ?? false, type: "main", }); @@ -26,7 +26,7 @@ import { ConfigModule, ConfigService } from "@nestjs/config"; const service = new PrismaWriteService(); service.setOptions({ writeUrl: config.get("db.writeUrl", { infer: true }), - maxWriteConnections: parseInt(config.get("db.writePoolMax", { infer: true })), + maxWriteConnections: parseInt(config.get("db.writePoolMax", { infer: true }), 10), e2e: config.get("e2e", { infer: true }) ?? false, type: "main", }); diff --git a/apps/api/v2/src/swagger/generate-swagger-script.ts b/apps/api/v2/src/swagger/generate-swagger-script.ts index 14b9b6fa47..96ef4a7b5b 100644 --- a/apps/api/v2/src/swagger/generate-swagger-script.ts +++ b/apps/api/v2/src/swagger/generate-swagger-script.ts @@ -1,5 +1,4 @@ import "dotenv/config"; -import process from "node:process"; import { bootstrap } from "../bootstrap"; import { createNestApp } from "../main"; diff --git a/biome.json b/biome.json index 96312d5b9c..fe8b052096 100644 --- a/biome.json +++ b/biome.json @@ -78,16 +78,6 @@ "linter": { "enabled": false }, "formatter": { "enabled": false } }, - { - "includes": ["apps/api/v2/**/*.ts", "apps/api/v2/**/*.controller.ts"], - "linter": { - "rules": { - "style": { - "useImportType": "off" - } - } - } - }, { "includes": ["**/*.tsx"], "javascript": { @@ -158,6 +148,20 @@ } } }, + { + "includes": ["apps/api/v2/**/*.ts", "apps/api/v2/**/*.controller.ts"], + "linter": { + "rules": { + "style": { + "useImportType": "off", + "noProcessEnv": "off" + }, + "correctness": { + "noProcessGlobal": "off" + } + } + } + }, { "includes": ["**/*.test.ts", "**/*.test.tsx", "**/*.e2e-spec.ts"], "linter": {