Cherrypyを使用してPython3.2上に小さなカスタムWebフレームワークを構築し、WSGIアプリケーションとSQLAlchemy Coreを構築しました(接続プールとテキストSQLステートメントの実行のためだけに)。
私が使用しているバージョン:
- Python:3.2.3
- CherryPy:3.2.2
- SQL Alchemy:0.7.5
- Psycopg2:2.4.5
リクエストごとに、sqlalchemy.engine.base.Engine
のconnect
メソッドを使用してDB接続がプールから取得されます。リクエストハンドラが終了すると、close
メソッドを使用して接続が閉じられます。例:擬似コード:
with db.connect() as db:
handler(db)
コンテキストdb.connect()
マネージャーは次のように定義されています。
@contextmanager
def connect(self):
conn = self.engine.connect()
try:
yield conn
finally:
conn.close()
これがこのタスクを実行するための正しい方法であることを願っています。ページハンドラーで物事がより複雑になるまで、それは機能しました。
変な振る舞いをしています。不明な理由により、ハンドラーが作業を終了する前に接続が閉じられることがあります。しかし、毎回ではありません!
観察によると、これはリクエストをすばやく連続して行う場合にのみ発生します。リクエストの合間に少し休止すると、接続が閉じられず、リクエストは正常に終了します。しかしとにかく、これは毎回起こるわけではありません。リクエストの失敗/成功に、より具体的なパターンは見つかりませんでした。
コンテキストマネージャーによって接続が閉じられていないことを確認しました。その時点ですでに閉鎖されています。
私の質問: 接続がいつ、なぜ、どのコードで閉じられているかを知る方法は?
デバッグしてみました。sqlalchemy.engine.base.Connection
のメソッドにブレークポイントを設定しましclose
たが、このコードに到達する前に接続が閉じられます。これは奇妙です。
ヒントや助けをいただければ幸いです。
*編集* zzzeekによって要求された情報:
「接続が閉じられている」の症状:これまで明確にされていなかったことをお詫びします。sqlalchemy.engine.Connection
閉まっているのです。
ハンドラーでは、データベースからデータを取得するためにsqlalchemy.engine.base.Connection
のメソッドを呼び出しています(selectステートメント)。executeを呼び出す前にプロパティをチェックしているので、これは閉じexecute
ていると言えます。sqlalchemy.engine.Connection
closed
ここにトレースバックを投稿できますが、おそらくそこに表示されるのは、DBラッパーライブラリで実行する前に例外が発生することだけです(接続が閉じているため)。
このチェックを削除すると(そしてexecute
メソッドを実行させると)、SQLAlchemyはこの例外を発生させます:http: //pastebin.com/H6052yca
zzzeekが言及した同時性の問題について。謝罪しなければなりません。さらに観察した後、状況は少し異なります。
これは、エラーを呼び出す方法の正確な手順です。
Request for HandlerA. Everything ok.
Wait moment (about 10-20s).
Request for HandlerB. Everything ok.
Request for HandlerA. Everything ok.
Immediate request for HandlerB. Error!
Immediate request for HandlerB. Error!
Immediate request for HandlerB. Error!
Wait moment (about 10-20s).
Request for HandlerB. Everything ok.
pool_size=5のデフォルトのSQLAlchemyプーリングクラスを使用しています。
実際のコードがないと奇跡を起こすことはできないことを私は知っています。しかし、残念ながら、私はそれを共有することはできません。このタイプのエラーをデバッグするためのベストプラクティスはありますか?または、唯一のオプションは、ステップバイステップでより深くデバッグし、それを理解しようとすることですか?
別の観察:
デバッガー(WingIDE)でサーバーを起動すると、エラーが発生しません。おそらく、デバッガーがコードを解釈するときに非常に遅いため、2番目の要求(RequestB)が処理される前に接続が何らかの形で「修復」されます。