Next.js standalone is single-process, so one container only used one CPU core. A load test hit a hard ceiling at ~60-65 req/sec with one core pegged at 133% while 3 cores sat idle. Now runs as pawfeed-1/2/3 behind an NPM least_conn upstream, verified via load test showing CPU spread evenly across all three replicas. Also caps the Prisma pg pool per-replica via DB_POOL_MAX so 3 replicas stay well under the Supabase pooler's connection limit.
39 lines
1.3 KiB
TypeScript
39 lines
1.3 KiB
TypeScript
import "server-only";
|
|
import { PrismaClient } from "@prisma/client";
|
|
import { PrismaPg } from "@prisma/adapter-pg";
|
|
import { Pool } from "pg";
|
|
|
|
/**
|
|
* Prisma 7 singleton — self-hosted Docker deployment, not Vercel.
|
|
* Uses @prisma/adapter-pg with a pg Pool for a direct Supabase connection.
|
|
*/
|
|
|
|
const globalForPrisma = globalThis as unknown as {
|
|
prisma: PrismaClient | undefined;
|
|
};
|
|
|
|
function createPrismaClient(): PrismaClient {
|
|
const databaseUrl = process.env.DATABASE_URL;
|
|
|
|
if (!databaseUrl) {
|
|
throw new Error(
|
|
"DATABASE_URL environment variable is not set. " +
|
|
"Please add it to .env.local with your Supabase connection string."
|
|
);
|
|
}
|
|
|
|
// pg defaults to max: 10 per process. With 3 replicas (docker-compose.yml)
|
|
// that's up to 30 concurrent connections — well under the Supabase
|
|
// pooler's 200 max client connections (verified 2026-08-16), so 10/replica
|
|
// stays the default here. Override via DB_POOL_MAX if that limit changes.
|
|
const poolMax = Number(process.env.DB_POOL_MAX) || 10;
|
|
const adapter = new PrismaPg(
|
|
new Pool({ connectionString: databaseUrl, max: poolMax })
|
|
);
|
|
return new PrismaClient({ adapter });
|
|
}
|
|
|
|
export const prisma = globalForPrisma.prisma ?? createPrismaClient();
|
|
|
|
if (process.env.NODE_ENV !== "production") globalForPrisma.prisma = prisma;
|