Posted at

GAE/py + SQLAlchemyで "2062, Cloud SQL socket open failed"

More than 1 year has passed since last update.


エラー遭遇

Google AppEngine Standard Environmentにデプロイしている、

pythonのサーバからCloud SQLへSQLAlchemyを用いて接続していましたが、

単発での接続では問題がなかったのに、連続稼働していると、以下のようなエラーが起きました。

OperationalError: (_mysql_exceptions.OperationalError) (2062, 'Cloud SQL socket open failed with error: Transport endpoint is not connected')

SQLAlchemyのエラーはSQLAlchemyのエラー回避備忘録などが大変参考になりましたが、該当するエラーはありませんでした。

というか、Cloud SQLと言っているのでGCP上でのエラーと思われます。

発生箇所はConnectionを貼るところでした。

taskを分割して別スレッドで連続して作業していると、突然コネクションが貼れなくなるようです。

こんな感じでした。


解決方法

検索するとすぐに出てくるのですが、とても簡単な話で、SQLサーバへの接続がスレッドごとにきちんとcloseされていないためでした。

コメントが違うエラーでしたが中身は同じで、12個以上のコネクションを同時に張ってはいけないようです。

FAQにもちゃんと記載がありました。


スタンダード環境で動作する各 App Engine インスタンスは、Google Cloud SQL インスタンスに対する同時接続数が最大 12 個に制限されます。



SQLAlchemyでの切断

SQLAlchemyで、query等にSessionを使っていました。

sessionオブジェクトにもcloseがあるのですが、これは厳密にはConnectionと対応していないようで、

sessionをcloseしてるにもかかわらず、相変わらずエラーが起きていました。

from sqlalchemy import create_engine

from sqlalchemy.orm import sessionmaker

engine = create_engine(url, encoding='utf8', echo=False)
Session = sessionmaker(bind=engine)
session = Session()
...
# ちゃんとcloseしていてもエラーが起きる
session.close()

SQLAlchemyではConnectionのPoolが使用されていて、connectionを再利用するため?にpool内で接続が維持されるようです。

上のスレッドで紹介されていましたが、単発で使って、別スレッド等でコネクションを共有されないような場合ではpoolをdisableにすれば、毎回connectionがcloseされるようです。

disableにする最も簡単な方法はengineを作るときにNullPoolを指定することです。

from sqlalchemy.pool import NullPool

# poolclassにNullPoolを指定するとpoolがdisableになる
engine = create_engine(url, poolclass=NullPool)
Session = sessionmaker(bind=engine)
session = Session()
...
# エラーが起きなくなった!
session.close()

他にも方法があるかと思いますが、今回はこのような対処をしました。

SQLAlchemyを使っていれば常識なのかもしれませんね、、以上です。