アプリケーション名を設定する
多くのプロセスを実行する予定の場合は、それらの接続元を知る必要があります。PGBouncerはこれをに非表示にしpg_stat_activity
ます。application_name
必要な情報を慎重に設定してこれを解決します。
# Sets the application name for this connection in the form of
# application-name:user@host
prog = os.path.basename(sys.argv[0]) or 'desjob'
username = pwd.getpwuid (os.getuid ()).pw_name
hostname = socket.gethostname().split(".")[0]·
args.setdefault('connect_args', {'application_name': "%s:%s@%s" %
(prog, username, hostname)})
args.setdefault('isolation_level', "AUTOCOMMIT")
engine = create_engine(url, **args)
セッションを優先
Engineオブジェクトからのリクエストは、複数の接続を生成して保持できるため、セッションを使用します。Postgresへの接続はそれほど高価ではありませんが、PGBouncerを使用すればさらに安価です。NullPool
Postgresに表示される接続が実際に使用されている接続のみになるように、常に使用します。
from sqlalchemy.pool import Pool, NullPool
engine = create_engine(uri, poolclass=NullPool)
アイドルトランザクションを排除する
PGBouncerを使用してスケーリングすることが目的の場合、トランザクションが開いたままになるのを避けることが不可欠です。これを行うには、有効autocommit
にする必要があります。これはSQLAlchemyでは簡単ではありません...「オートコミット」と呼ばれるものを設定できる場所は3つあります。
psycopg2自動コミット
conn = psycopg2.connect(uri)
conn.autocommit = True
SQLAlchemyはその下で何が起こっているのかを知る必要があるため、安全でないと推定されます。
セッション自動コミット
Session = sessionmaker(bind=engine, autocommit=True)
session = Session()
これには、慎重で明示的な処理が必要です。
session.begin()
session.execute(...)
session.rollback()
関数呼び出しと例外処理は非常に困難でbegin()
あり、commit()
ネストできないため
です。
def A():
session.begin()
...
session.rollback()
def B():
session.begin()
try:
A() # error, already open
このモードでは、psycopg2 autocommit
はFalse
(デフォルト)のように見えます。
エンジンの自動コミット
エンジンの"AUTOCOMMIT"
作成時にエンジン分離モードを設定すると、既存のコードを変更する必要のない新しいデフォルトの動作が確立されます。
engine = create_engine(uri, isolation_level="AUTOCOMMIT")
このモードでは、psycopg2 autocommit
はTrue
ここでの主要な問題は、コードのブロックがトランザクションでラップされることを保証する唯一の方法が、ステートメントを手動で発行することであることです。
session.execute("BEGIN")
#...
session.execute("COMMIT")