Я размещаю два приложения python (app1 и app2) на машине с Ubuntu (16.04) под одной и той же установкой с разными версиями python (2.7 и 3.7), оба основаны на фреймворке Flask с использованием Flask-SocketIO, работающем на uWSGI ( 2.0.17.1) за прокси Nginx.
Мне удалось успешно реализовать поддержку websocket в версии 2.7, но я не смог сделать то же самое в 3.7.
Конфигурация Nginx и uwsgi одинаковы, за исключением разных плагинов для uwsgi (версия Python)
В обоих случаях я использую сервер uwsgi websocket (через SocketIO) с очередью redis.
Помимо проблемы websocket app2 работает просто отлично.
Python Setup
Python 2.7 Libs:
Настой == 0.12.2
Колба-SocketIO == 2.9.4
GEvent == 1.2.2
greenlet == 0.4.13
Python 3,7 Libs:
Настой == 1.0.2
Колба-Script == 2.0.6
GEvent == 1.3.7
greenlet == 0.4.15
uWSGI - 2.0.17.1
Рабочая конфигурация приложения 1:
__ __ INIT. Ру
app = Flask(__name__)
# SocketIO
try: # This step is required only for version deployed on UWSGI
import uwsgi
socketio = SocketIO(app, message_queue=app.config['REDIS_QUEUE_URL'])
except ImportError:
print 'Application runs outside of uWSGI context'
socketio = SocketIO(app)
manage.py
from flask-script import Manager
from app1 import app
@manager.command
def runserver(host = None, port = None, socket = True):
if not host:
host = 'localhost'
if not port:
port = 5000
if socket:
socketio.run(app)
else:
app.run(host, port, debug=False)
app1.ini
[uwsgi]
plugins-dir = /usr/local/lib/uwsgi
plugins = python27
#application's base folder
base = /home/ubuntu/app1
#python module to import
app = manage
module = %(app)
home = %(base)/venv
virtualenv = %(base)/venv
pythonpath = %(base)
#socket file's location
socket = %(base)/app1.sock
#permissions for the socket file
chmod-socket = 666
callable = app
logto = /var/log/uwsgi/%n.log
processes = 20
http-websockets = true
gevent = 500
vacuum = true
die-on-term = true
enable-threads = true
master = true
app1-сайт
server {
listen 1014 ssl default_server;
server_name server_name_1;
access_log /var/log/nginx/app1_access_log;
error_log /var/log/nginx/app1_error_log;
auth_basic off;
# SSL only
ssl on;
ssl_certificate /etc/nginx/ssl/nginx.crt;
ssl_certificate_key /etc/nginx/ssl/nginx.key;
ssl_session_timeout 5m;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
location /socket.io/ {
include uwsgi_params;
uwsgi_pass unix:/home/ubuntu/app1/app1.sock;
proxy_http_version 1.1;
proxy_read_timeout 180s;
proxy_buffering on;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
}
location / {deny all;}
location = /app1{ rewrite ^ /app1/; }
location /app1{
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_pass http://localhost:8080;
proxy_read_timeout 90;
proxy_redirect http://server:8080 https://server_name_1:1014/app1;
try_files $uri @app1; }
location @app1{
include uwsgi_params;
uwsgi_param SCRIPT_NAME /app1;
uwsgi_modifier1 30;
uwsgi_read_timeout 180s;
uwsgi_send_timeout 180s;
proxy_read_timeout 180s;
uwsgi_pass unix:/home/ubuntu/app1/app1.sock;
}}
Конфигурация приложения 2
__ __ INIT. Ру
def create_app():
...
app = Flask(__name__)
socket_io.init_app(app, message_queue = app.config['REDIS_URL'])
...
return app
wsgi.py
import uwsgi
from gevent.monkey import patch_all
patch_all()
print('Patching all!')
from app2 import create_app
application = create_app()
app2.ini
[uwsgi]
plugins-dir = /usr/local/lib/uwsgi
plugins = python37
#application's base folder
base = /home/ubuntu/app2
home = %(base)/venv
virtualenv = %(base)/venv
pythonpath = %(base)
mount = /app2=%(base)/wsgi.py
callable = application
socket = %(base)/app2.sock
chmod-socket = 666
chdir = %(base)
attach-daemon = %(virtualenv)/bin/celery -A celery_worker.celery worker
attach-daemon = %(virtualenv)/bin/celery -A celery_worker.celery beat
logto = /var/log/uwsgi/%n.log
processes = 20
vacuum = true
die-on-term = true
enable-threads = true
master = true
manage-script-name = true
http-websockets = true
gevent = 5000
#Workaround for flask send_file() failing on python 3 and uwsgi
wsgi-disable-file-wrapper = true
app2-сайт
server {
listen 1015 ssl default_server;
server_name server_name_2;
access_log /var/log/nginx/app2_access_log;
error_log /var/log/nginx/app2_error_log;
auth_basic off;
# SSL only
ssl on;
ssl_certificate /etc/nginx/ssl/nginx.crt;
ssl_certificate_key /etc/nginx/ssl/nginx.key;
ssl_session_timeout 5m;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
location /socket.io/ {
include uwsgi_params;
uwsgi_buffering off;
uwsgi_pass unix:/home/ubuntu/app2/app2.sock;
proxy_http_version 1.1;
proxy_read_timeout 180s;
proxy_buffering on;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
}
location / {deny all;}
location = /app2 { rewrite ^ /app2/; }
location /app2/ {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_pass http://localhost:8080;
proxy_read_timeout 90;
proxy_redirect http://localhost:8080 https://server_name_2:1015/app2;
try_files $uri @app2; }
location @app2 {
include uwsgi_params;
uwsgi_read_timeout 180s;
uwsgi_send_timeout 180s;
proxy_read_timeout 180s;
uwsgi_pass unix:/home/ubuntu/app2/app2.sock;
}}
Судя по моим исследованиям, проблема в uWSGI, по какой-то причине он не получает никаких вызовов wss. С точки зрения клиента сокетное соединение Завершено вместо 101 Ожидание .
Проблема сохраняется независимо от того, каким клиентом я пользуюсь.
В приложении 1 я вижу каждую попытку и ошибку подключения к сокету в лог-файлах nginx и uwsgi (vassal), в случае app2 я вижу только 499 ошибок для каждой попытки подключения к сокету, без соответствующей записи в журнале вассала.
Изначально я обвинял сервер uwsgi websocket, на котором можно было разместить только 1 приложение, но я могу свободно дублировать app1 столько раз, сколько захочу, под разными вассалами и сайтами nginx, соединения с websocket хороши.
Что я пробовал
- переключение между версиями lib (gevent должен быть> = 1.3.6)
- используя сокет http вместо unix one
- эксперименты с путями
- жонглирование размерами буфера на nginx и uwsgi
Известны ли какие-либо проблемы с интеграцией Python 3.7 & uwsgi и SocketIO? У меня нет идей.