From 59b766d0712042646ffb8de4f8e969047c52f8d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yusuf=20=C4=B0pek?= Date: Tue, 24 Feb 2026 18:10:36 +0300 Subject: [PATCH] chore(infra): gate DB pool debug logs and de-duplicate rate-limit cleanup timer --- .env.example | 2 ++ lib/db.ts | 16 ++++++++++------ lib/rate-limit.ts | 19 ++++++++++++++----- 3 files changed, 26 insertions(+), 11 deletions(-) diff --git a/.env.example b/.env.example index d0c8b82..20515d7 100644 --- a/.env.example +++ b/.env.example @@ -5,6 +5,8 @@ # ============================================================================ # PostgreSQL connection string DATABASE_URL="postgresql://user:password@localhost:5432/openframe?schema=public" +# Enable PostgreSQL pool connect/acquire debug logs (set to "true" only when debugging) +DB_POOL_DEBUG="false" # ============================================================================ # AUTHENTICATION - NextAuth.js diff --git a/lib/db.ts b/lib/db.ts index fdabba0..05ba5a4 100644 --- a/lib/db.ts +++ b/lib/db.ts @@ -10,6 +10,8 @@ const globalForPool = globalThis as unknown as { pgPool: Pool | undefined; }; +const isDbPoolDebugEnabled = process.env.DB_POOL_DEBUG === 'true'; + function createPool(connectionString: string): Pool { // Prevent multiple pools from being created during development (Next.js hot reload) if (globalForPool.pgPool) { @@ -31,13 +33,15 @@ function createPool(connectionString: string): Pool { // Don't crash the app on unexpected pool errors }); - pool.on('connect', () => { - console.debug('New database connection established'); - }); + if (isDbPoolDebugEnabled) { + pool.on('connect', () => { + console.debug('New database connection established'); + }); - pool.on('acquire', () => { - console.debug('Connection acquired from pool'); - }); + pool.on('acquire', () => { + console.debug('Connection acquired from pool'); + }); + } // Store pool globally to prevent multiple instances during development if (process.env.NODE_ENV !== 'production') { diff --git a/lib/rate-limit.ts b/lib/rate-limit.ts index eefe8be..dc09327 100644 --- a/lib/rate-limit.ts +++ b/lib/rate-limit.ts @@ -1,6 +1,12 @@ import { db } from '@/lib/db'; import { NextResponse } from 'next/server'; +const RATE_LIMIT_CLEANUP_INTERVAL_MS = 5 * 60 * 1000; + +const globalForRateLimitCleanup = globalThis as unknown as { + rateLimitCleanupIntervalStarted?: boolean; +}; + interface RateLimitConfig { windowMs: number; // Time window in milliseconds maxRequests: number; // Max requests per window @@ -172,12 +178,15 @@ export async function cleanupRateLimits(): Promise { } } -// Start cleanup interval when the module is loaded (for self-hosted servers) -// Cleanup runs every 5 minutes to remove expired rate limit entries -if (typeof setInterval !== 'undefined') { - setInterval(() => { +// Start cleanup interval once per process to avoid duplicate scheduling on module reload. +if (!globalForRateLimitCleanup.rateLimitCleanupIntervalStarted && typeof setInterval !== 'undefined') { + const interval = setInterval(() => { cleanupRateLimits().catch(console.error); - }, 5 * 60 * 1000); + }, RATE_LIMIT_CLEANUP_INTERVAL_MS); + + // Avoid keeping Node.js process alive because of housekeeping timers. + interval.unref?.(); + globalForRateLimitCleanup.rateLimitCleanupIntervalStarted = true; } /**