テック技報最新号へ →
コード

Postgres: PgBouncer の transaction モードではセッション状態が別の接続に漏れる。SET LOCAL と xact 系ロックを使う

transaction モードの PgBouncer は、トランザクションが終わるたびにサーバー接続を別のクライアントに回す。SET、セッション単位のアドバイザリロック、LISTEN、一時テーブルなど「セッションに残る状態」は、他人の接続に残ったり自分の次のクエリから消えたりする。

@amitsinha__07 · 投稿 2026-10-24
#postgres#pgbouncer#infra#connection-pool

壊れる例

sql
SET search_path = tenant_42;        -- 次のトランザクションは別のサーバー接続かもしれない
SELECT pg_advisory_lock(123);       -- ロックを持ったサーバー接続が他のクライアントに渡る
  • SET statement_timeout を付けたつもりが、別のクライアントの接続に効いてしまう。
  • セッション単位のアドバイザリロックを解放できない/他人が解放してしまう。

安全な書き方

sql
BEGIN;
SET LOCAL search_path = tenant_42;          -- トランザクション終了で元に戻る
SET LOCAL statement_timeout = '60s';
SELECT pg_advisory_xact_lock(123);          -- COMMIT / ROLLBACK で自動解放
-- ...
COMMIT;

注意点

  • LISTEN / NOTIFY の受信、WITH HOLD カーソル、セッションをまたぐ一時テーブルは transaction モードでは使えない。必要なら session モードのプールか直接接続を別に用意する。
  • 名前付きプリペアドステートメントは、PgBouncer 1.21 以降なら max_prepared_statements を 0 より大きくするとプロトコルレベルで扱える。それより古い版ではドライバ側で無効にする必要がある。
  • マイグレーションツールがセッションロックを使う場合(多くのツールが使う)は、PgBouncer を通さず直接接続で流す。

出典

X の元の投稿を開く