1

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.Engineconnectメソッドを使用して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.Connectionclosed

ここにトレースバックを投稿できますが、おそらくそこに表示されるのは、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)が処理される前に接続が何らかの形で「修復」されます。

4

1 に答える 1

4

終日のデバッグ後。私は問題を見つけました。

残念ながら、SQLAlchemyとは直接関係がありませんでした。したがって、質問は削除する必要があります。しかし、皆さんは私を助けようとしたので、私は私自身の質問に答えます。そして多分、誰かがいつかこれが役に立つと思うでしょう。

基本的に、エラーは、マルチスレッド環境でうまく機能しなかったカスタムのパブリッシュ/サブスクライブメソッドが原因で発生しました。

私はコードを1行ずつステップしてみました...それは機能していませんでした(質問で説明したように)。それで、私は何が起こっているかについての非常に詳細なログを生成し始めました。

それでも、クラッシュする数行前にモデルで参照されているConnectionオブジェクトのアドレスが変更されていることに気付くまで、すべてが正常に見えました。これは実際には、何かが別のConnectionオブジェクトをモデルに割り当て、その接続オブジェクトがすでに閉じられていることを意味します。

だからレッスンはです。すべてが正しいように見えたら、問題のあるオブジェクトのrepr()を印刷/ログに記録します。

コメント投稿者の皆さん、ありがとうございました。

于 2012-08-27T16:27:30.873 に答える