Prisma の connection pool
Prisma の connection pool のデフォルト値は、CPU の数で決まっている。
CPUの数 x 2 + 1
CPU が1つなら、3だ。
Prisma の connection pool timeout は、10秒。
via. Connection pool
上限値の変更方法
DATABASE_URL
で指定する。
DATABASE_URL="mysql://${DB_USER}:${DB_PASS}@${DB_HOST}/${DB_NAME}?schema=public&connection_limit=30&pool_timeout=60"
こんな感じで指定するだけ。
当然、CPU への負荷は上がるので、根本的には、CPU の数を増やすのが良い。予算やインフラチームと相談しよう。
テストサーバで、大量に seed したい時とか、そういう時に使うのが良い。
via. Connection pool
Transaction の場合
Transaction APIを使うと、ちょっと負荷をかけると Transaction API error: Transaction not found
と言うようなエラーが出る。あれこれ調べると、3.9 で解消しているとされているが、それ以上のバージョンでやっても出る。これは、どうやら Transaction API の maxWait
と timeout
を指定してあげれば解決するらしい。maxWait のデフォルト値は2秒、timeout は5秒
await prisma.$transaction(
async (tx) => {
// Code running in a transaction...
},
{
maxWait: 5000, // default: 2000
timeout: 10000, // default: 5000
}
)
via. Transactions and batch queries
が、これやってもダメなこともあるようだ。previewFeature 卒業してる 4 系の最新バージョンを使うと改善されているのかも知れない。(試してない)
そもそもの接続を減らす
warn(prisma-client) There are already 10 instances of Prisma Client actively running.
こういう警告が出る。警告が出ても Local では問題なく動くが、Production build で connection pool の上限に引っかかってエラーになることがある。
これは、new PrismaClient()
するたびに増えていくため、1度だけ呼ぶようにする。
具体的には、lib/prisma.ts
などを作成し、それを必要なところで呼ぶようにする。
import { PrismaClient } from '@prisma/client';
const globalForPrisma = global as unknown as { prisma: PrismaClient };
export const prisma =
globalForPrisma.prisma ||
new PrismaClient();
if (process.env.NODE_ENV !== 'production') globalForPrisma.prisma = prisma;
import { prisma } from '../../lib/prisma.ts';
export const ....
const hoge = await prisma.moge.findMany({...})
...
こんな感じで。
via. Best practice for instantiating PrismaClient with Next.js
$disconnect()
すべきなのか?
これは、ケースバイケースだとしか言いようがないが、私が Next.js でよく作っている API のようなアプリケーションの場合、やらない方が良いようだ。
$disconnect()を呼び出すと , Prisma Clientは、
- beforeExit hook を実行します
- Query Engine の子プロセスを終了し、全ての接続を閉じます
GraphQL API のような長時間稼働するアプリケーションでは、常にリクエストを処理するため、各リクエストの後に $disconnect() を実行する意味がありません。 - 接続の確立に時間がかかるため、各リクエストで接続を切断すると、アプリケーションの速度が低下します。
長時間実行するアプリケーションでは、接続数が多くなりすぎないように、アプリケーション全体で単一の PrismaClient のインスタンスを使用することをお勧めします。
via. Connecting and disconnecting
とあるので、API のようなアプリケーションでは、$disconnect()
を呼び出すのは良くない。
逆に、テスト等で、終わったらきちんと切断したい場合は、明示的に $disconnect()
を呼ぶ。
まとめ
- Connection pool の上限は、CPU で決まるので、実行するサーバのスペックを検討する
- 一時的に接続数を増やしたいなどの場合は、DATABASE_URL で指定する
- Transaction は、個別に指定する
- シングルインスタンスを使う
-
$disconnect()
は API のようなサービスの場合は、しない。