Prisma の connection pool の設定あれこれ

## Prisma の connection pool

Prisma の connection pool のデフォルト値は、CPU の数で決まっている。

```
CPUの数 x 2 + 1
```

CPU が1つなら、3だ。


Prisma の connection pool timeout は、10秒。

via. [Connection pool](https://www.prisma.io/docs/concepts/components/prisma-client/working-with-prismaclient/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](https://www.prisma.io/docs/concepts/components/prisma-client/working-with-prismaclient/connection-pool)


## Transaction の場合

Transaction APIを使うと、ちょっと負荷をかけると ```Transaction API error: Transaction not found``` と言うようなエラーが出る。あれこれ調べると、3.9 で解消しているとされているが、それ以上のバージョンでやっても出る。これは、どうやら Transaction API の ```maxWait``` と ```timeout``` を指定してあげれば解決するらしい。maxWait のデフォルト値は2秒、timeout は5秒

```typescript
await prisma.$transaction(
  async (tx) => {
    // Code running in a transaction...
  },
  {
    maxWait: 5000, // default: 2000
    timeout: 10000, // default: 5000
  }
)
```

via. [Transactions and batch queries](https://www.prisma.io/docs/concepts/components/prisma-client/transactions)

が、これやってもダメなこともあるようだ。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``` などを作成し、それを必要なところで呼ぶようにする。

```typescript: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;
```

```pages/api/index.tsx
import { prisma } from '../../lib/prisma.ts';

export const ....
 const hoge = await prisma.moge.findMany({...})
...
```
こんな感じで。

via. [Best practice for instantiating PrismaClient with Next.js](https://www.prisma.io/docs/guides/database/troubleshooting-orm/help-articles/nextjs-prisma-client-dev-practices)

## ```$disconnect()``` すべきなのか？

これは、ケースバイケースだとしか言いようがないが、私が Next.js でよく作っている API のようなアプリケーションの場合、やらない方が良いようだ。

> $disconnect()を呼び出すと , Prisma Clientは、
>
> 1. beforeExit hook を実行します
> 2. Query Engine の子プロセスを終了し、全ての接続を閉じます
>
> GraphQL API のような長時間稼働するアプリケーションでは、常にリクエストを処理するため、各リクエストの後に $disconnect() を実行する意味がありません。 - 接続の確立に時間がかかるため、各リクエストで接続を切断すると、アプリケーションの速度が低下します。
> 
> 長時間実行するアプリケーションでは、接続数が多くなりすぎないように、アプリケーション全体で単一の PrismaClient のインスタンスを使用することをお勧めします。

via. [Connecting and disconnecting](https://www.prisma.io/docs/concepts/components/prisma-client/working-with-prismaclient/connection-management)

とあるので、API のようなアプリケーションでは、```$disconnect()``` を呼び出すのは良くない。
逆に、テスト等で、終わったらきちんと切断したい場合は、明示的に ```$disconnect()``` を呼ぶ。




## まとめ

- Connection pool の上限は、CPU で決まるので、実行するサーバのスペックを検討する
- 一時的に接続数を増やしたいなどの場合は、DATABASE_URL で指定する
- Transaction は、個別に指定する
- シングルインスタンスを使う
- ```$disconnect()``` は API のようなサービスの場合は、しない。