PostWSデータベースと通信するためにSQLAlchemyを使用してFlaskアプリケーションを実行するuWSGI + Nginxを使用してアプリケーションウェブサーバーをセットアップしようとしています。
ウェブサーバーにリクエストを送信すると、他のすべての応答は500エラーになります。
エラーは:
Traceback (most recent call last):
File "/var/env/argos/lib/python3.3/site-packages/sqlalchemy/engine/base.py", line 867, in _execute_context
context)
File "/var/env/argos/lib/python3.3/site-packages/sqlalchemy/engine/default.py", line 388, in do_execute
cursor.execute(statement, parameters)
psycopg2.OperationalError: SSL error: decryption failed or bad record mac
The above exception was the direct cause of the following exception:
sqlalchemy.exc.OperationalError: (OperationalError) SSL error: decryption failed or bad record mac
エラーは単純なFlask-SQLAlchemy
方法:
result = models.Event.query.get(id)
uwsgi
はsupervisor
によって管理されており、設定があります:
[program:my_app]
command=/usr/bin/uwsgi --ini /etc/uwsgi/apps-enabled/myapp.ini --catch-exceptions
directory=/path/to/my/app
stopsignal=QUIT
autostart=true
autorestart=true
uwsgi
の設定は次のようになります:
[uwsgi]
socket = /tmp/my_app.sock
logto = /var/log/my_app.log
plugins = python3
virtualenv = /path/to/my/venv
pythonpath = /path/to/my/app
wsgi-file = /path/to/my/app/application.py
callable = app
max-requests = 1000
chmod-socket = 666
chown-socket = www-data:www-data
master = true
processes = 2
no-orphans = true
log-date = true
uid = www-data
gid = www-data
私が得ることができる最も遠いことは、それがuwsgiのフォークと関係があるということです。しかし、それを超えて私は何をする必要があるのかはっきりしていません。
問題はuwsgiの分岐でした。
マスタープロセスで複数のプロセスを操作する場合、uwsgiはマスタープロセスでアプリケーションを初期化してから、各ワーカープロセスにアプリケーションをコピーします。問題は、アプリケーションの初期化時にデータベース接続を開いた場合、同じ接続を共有する複数のプロセスがあり、上記のエラーが発生することです。
解決策は、lazy
wsgiの構成オプション を設定することです。これにより、各プロセスでアプリケーションの完全なロードが強制されます。
lazy
レイジーモードを設定します(マスターではなくワーカーにアプリを読み込みます)。
Copy-on-Writeセマンティクスは使用できないため、このオプションはメモリ使用量に影響を与える可能性があります。レイジーを有効にすると、ワーカーのみがuWSGIのリロード信号によってリロードされます。マスターは生き続けます。そのため、uWSGI構成の変更は、マスターによるリロード時に取得されません。
lazy-apps
オプションもあります:
lazy-apps
マスターではなく各ワーカーにアプリをロードします。
Copy-on-Writeセマンティクスは使用できないため、このオプションはメモリ使用量に影響を与える可能性があります。レイジーとは異なり、これはアプリケーションのロード方法にのみ影響し、リロード時のマスターの動作には影響しません。
このuwsgi構成は私にとってはうまくいきました:
[uwsgi]
socket = /tmp/my_app.sock
logto = /var/log/my_app.log
plugins = python3
virtualenv = /path/to/my/venv
pythonpath = /path/to/my/app
wsgi-file = /path/to/my/app/application.py
callable = app
max-requests = 1000
chmod-socket = 666
chown-socket = www-data:www-data
master = true
processes = 2
no-orphans = true
log-date = true
uid = www-data
gid = www-data
# the fix
lazy = true
lazy-apps = true
別の方法として、エンジンを廃棄することもできます。これが私が問題を解決した方法です。
このような問題は、アプリの作成中、つまりアプリ自体を作成するモジュールにクエリがある場合に発生する可能性があります。それが示す場合、エンジンは接続のプールを割り当て、次にuwsgiフォークを割り当てます。
'engine.dispose()'を呼び出すと、接続プール自体が閉じられ、誰かがもう一度クエリを開始するとすぐに新しい接続が確立されます。したがって、アプリを作成するモジュールの最後でこれを行うと、UWSGIフォークの後に新しい接続が作成されます。