Flask-SQLAlchemyでMySQLを使っていてハマった事象について。
発生事象
Flaskアプリケーションを起動して長時間(8時間くらい?)経過後にブラウザでアクセスするとInternal Server Error。エラーログは下記の内容。
sqlalchemy.exc.OperationalError: (pymysql.err.OperationalError) (2013, 'Lost connection to MySQL server during query')
Internal Server Error発生後、ブラウザで再読み込みするとエラーは解消される。
が、さらに長時間経過すると再び同様のエラーが発生。
環境
- Python 3.9.5
- MySQL 5.7.34
- Flask 2.0.0
- Flask-SQLAlchemy 2.4.4
- PyMySQL 1.0.2
原因と対策
どうやら長時間経過するとコネクションプールが死んでしまう模様。
これを解消するにはDBアクセスの前にpingを飛ばしてやる、すなわち SELECT 1
のような特に何もしないSQLを投げてコネクションプールを復活させてやればOK。
この方法はSQLAlchemyの機能として提供されており、デフォルトでは使用しない設定となっている。
create_engine
の引数に pool_pre_ping=True
を渡せとのことだったが、A Minimal Applicationをどう改修したらいいものやら、いろいろ試した結果以下の方法に落ち着いた。
app = Flask(__name__)
app.config['SQLALCHEMY_ENGINE_OPTIONS'] = {
'pool_pre_ping': True
}
とりあえず長時間経過してもエラーは出なくなった。
わからないこと
- MySQL以外のDBMSでは発生しないのか?