fix: Supabase Transaction pool mode 対応のため DB ドライバを postgres-js に切り替え#146
fix: Supabase Transaction pool mode 対応のため DB ドライバを postgres-js に切り替え#146KinjiKawaguchi merged 1 commit intomainfrom
Conversation
There was a problem hiding this comment.
Pull request overview
DB ドライバを drizzle-orm/node-postgres(pg)から drizzle-orm/postgres-js(postgres)へ切り替え、Supabase の Transaction pool mode(prepared statement 非対応)や SSL 証明書検証まわりの接続問題を回避するための変更です。
Changes:
- Drizzle の接続先を
node-postgresベースからpostgres-jsベースへ変更 postgres(connectionString, { prepare: false })を使用するように接続初期化を更新- 依存関係を
pg/@types/pgからpostgresに置き換え
Reviewed changes
Copilot reviewed 2 out of 3 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
| src/infrastructure/drizzle/client.ts | Drizzle クライアント生成を postgres-js に切り替え、prepared statement を無効化 |
| package.json | pg/@types/pg を削除し postgres を追加 |
| package-lock.json | ロックファイル上の依存関係を postgres へ更新(pg 関連を削除) |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| export function getDb() { | ||
| return drizzle(getPool(), { schema }); | ||
| return drizzle(getClient(), { schema }); | ||
| } |
There was a problem hiding this comment.
📝 Info: getDb() creates a new drizzle instance on every call
Each call to getDb() at src/infrastructure/drizzle/client.ts:19-21 creates a new drizzle() wrapper instance, even though the underlying postgres client is cached. This is the same pattern that existed before the migration (with drizzle(getPool(), { schema })), so it's not a regression. However, drizzle-orm recommends creating the drizzle instance once. The drizzle wrapper is lightweight, so this is unlikely to cause measurable performance issues, but caching the drizzle instance (similar to how client is cached) would be a minor improvement.
Was this helpful? React with 👍 or 👎 to provide feedback.
| import * as schema from "./schema"; | ||
|
|
||
| let pool: Pool | null = null; | ||
| let client: ReturnType<typeof postgres> | null = null; |
There was a problem hiding this comment.
📝 Info: No graceful shutdown hook for postgres.js client
The postgres client cached at src/infrastructure/drizzle/client.ts:5 is never explicitly closed (e.g., via client.end()). The old pg.Pool had the same issue — neither implementation registered a shutdown hook. With postgres.js, the client maintains a connection pool internally. In serverless or short-lived contexts this is fine (connections close on process exit), but in long-running services a graceful shutdown hook calling client.end() would be best practice. This is pre-existing and not introduced by this PR.
Was this helpful? React with 👍 or 👎 to provide feedback.
59a21b6 to
49ca25c
Compare
Supabase の Transaction pool mode(pgbouncer)は prepared statement を サポートしないため、Supabase が推奨する postgres-js + prepare:false の 構成に統一する。また node-postgres は最新の pg v9 で sslmode=require を verify-full として扱うようになり、Supabase の証明書チェーンで接続失敗する 問題があったが、postgres-js ではこの問題が発生しない。 - drizzle-orm/node-postgres → drizzle-orm/postgres-js に変更 - pg / @types/pg 依存を削除し postgres を追加 - prepare: false を明示して Transaction pool mode に対応 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
49ca25c to
75a95e2
Compare
| client = postgres(connectionString, { prepare: false }); | ||
| } |
There was a problem hiding this comment.
📝 Info: prepare: false disables prepared statements globally
Setting prepare: false at src/infrastructure/drizzle/client.ts:16 disables prepared statements for all queries through this client. The comment correctly explains this is needed for Supabase's Transaction pool mode (pgbouncer in transaction mode doesn't support prepared statements). This is a correct and necessary configuration choice, but it does mean a slight performance trade-off — repeated identical queries won't benefit from server-side prepared statement caching. Worth noting for anyone reading this code that this is an intentional trade-off, not an oversight.
Was this helpful? React with 👍 or 👎 to provide feedback.
Summary
DB ドライバを
drizzle-orm/node-postgres(pg) から Supabase 推奨のdrizzle-orm/postgres-js(postgres) に切り替える。Why
1. Transaction pool mode 対応
Supabase の Transaction pool mode(pgbouncer 経由、port 6543)は prepared statement をサポートしない。
postgres-jsのprepare: falseオプションを明示することで、プーラー経由の接続で安全にクエリを実行できる。2. SSL 証明書検証の問題
最新の
pg(v8.x 系の後期) はsslmode=requireをverify-fullのエイリアスとして扱うようになり、Supabase の証明書チェーンでSELF_SIGNED_CERT_IN_CHAINエラーが発生するようになった。これにより its-discord から接続できなくなる問題が発生していた。postgres-jsはこの挙動に影響されず、プーラー URL でそのまま接続できる。3. Supabase 公式推奨
Supabase の Drizzle 接続ドキュメントでも
postgres-js+prepare: falseが推奨されている。Changes
drizzle-orm/node-postgres→drizzle-orm/postgres-jspg/@types/pgを削除しpostgresを追加src/infrastructure/drizzle/client.tsでpostgres(connectionString, { prepare: false })を使用Test plan
npm run buildが成功することgetMemberByDiscordIdが正常動作することを確認