Flask-SocketIO + uWSGI。与骡子工作者一起发出

时间:2017-12-08 14:40:44

标签: python python-2.7 flask uwsgi flask-socketio

最近我在我的Flask应用程序中实现了WebSocket支持。

安装程序如下所示:     1. Python 2.7     2. Flask + Flask-SocketIo     3. SocketIO(客户端)     4. NGINX作为代理     5. uWSGI 2.0.13 +它带有Gevent的WebSocket(Monkey-patched)

我已经设法启用套接字连接,但我在UWSGI Workers,尤其是单个mule之间努力实现同步。

我有专门的UWSGI骡子监视一些东西并每隔30秒报告一次状态,并将其广播给连接的客户端。如果我允许我的任务在任何可用的工作者(不仅是专用的mule)上运行,则只通过完全相同的过程到达先前服务器的客户端,例如: 工作人员#6为(400 PID)和已建立的Socket连接提供客户端请求。 后来一个mule任务由同一个Worker提供服务,因此客户端收到了Emit)如果任何其他worker处理了该任务,则客户端不会缓存emit。

使用单一工作模式一切正常,但这显然是不可接受的解决方案。

以下是一些技术细节: uwsgi.ini

[uwsgi]
#application's base folder
base = /home/ubuntu/application_test

#python module to import
app = manage
module = %(app)

home = %(base)/venv
virtualenv = %(base)/venv
pythonpath = %(base)

#socket file's location
socket = %(base)/application_test.sock

#permissions for the socket file
chmod-socket = 666

#the variable that holds a flask application inside the module imported at 
line #6
callable = app

#location of log files
logto = /var/log/uwsgi/%n.log

processes = 10

#WebSocket
http-websockets = true

gevent = 1000
enable-threads = true
die-on-therm = true

vacuum = true

mule=%(base)/application_test/uwsgi_mules/metrics_mule.py

Flask App

(...)
from flask_socketio import SocketIO
app = Flask(__name__)
socketio = SocketIO(app,message_queue='redis://')
(...)

工人发出代码

socket = SocketIO(message_queue='redis://')

def broad_cast_server_info(state, health):
    socket.emit('sys_state', health)
    socket.emit('system_snapshot', state)

客户端

        socket.on('sys_state', function(data){
            (...)
            }
        });

如果我使用客户端socket.emit和确认响应,一切正常。

当我在mule中我只是导入socketio并在其上调用emit我面临上述问题。但是,如果我遵循: https://flask-socketio.readthedocs.io/en/latest/#emitting-from-an-external-process

每次mule工作时我都会收到redis错误。

  

文件" /home/ubuntu/application_test/venv/local/lib/python2.7/site-packages/flask_socketio/ init .py",第365行,发出       skip_sid = skip_sid,callback = callback,** kwargs)     文件" /home/ubuntu/application_test/venv/local/lib/python2.7/site-packages/socketio/server.py" ;,第228行,发出       ** kwargs)     文件" /home/ubuntu/application_test/venv/local/lib/python2.7/site-packages/socketio/pubsub_manager.py" ;,第66行,发出       ' skip_sid':skip_sid,' callback':callback})     文件" /home/ubuntu/application_test/venv/local/lib/python2.7/site-packages/socketio/redis_manager.py",第62行,在_publish中       return self.redis.publish(self.channel,pickle.dumps(data))     文件" /home/ubuntu/application_test/venv/local/lib/python2.7/site-packages/redis/client.py" ;,第2034行,发布       return self.execute_command(' PUBLISH',channel,message)     文件" /home/ubuntu/application_test/venv/local/lib/python2.7/site-packages/redis/client.py",第673行,在execute_command中       connection.send_command(*参数)     文件" /home/ubuntu/application_test/venv/local/lib/python2.7/site-packages/redis/connection.py" ;,第610行,在send_command中       self.send_packed_command(self.pack_command(*参数))     文件" /home/ubuntu/application_test/venv/local/lib/python2.7/site-packages/redis/connection.py",第585行,在send_packed_command中       self.connect()     文件" /home/ubuntu/application_test/venv/local/lib/python2.7/site-packages/redis/connection.py" ;,第489行,在连接中       引发ConnectionError(self._error_message(e))   redis.exceptions.ConnectionError:错误-2连接到redispass:6379。名称或服务未知。

PIP FREEZE:

alabaster==0.7.9
amqp==2.1.1
aniso8601==1.2.0
appdirs==1.4.3
astroid==1.4.8
Babel==2.3.4
beautifulsoup4==4.5.1
certifi==2017.11.5
chardet==3.0.4
click==6.7
decorator==4.0.11
defusedxml==0.5.0
dict2xml==1.5
dicttoxml==1.7.4
docopt==0.6.2
enum-compat==0.0.2
enum34==1.1.6
eventlet==0.21.0
Flask==0.12
Flask-Login==0.4.0
Flask-RESTful==0.3.5
flask-restful-swagger-2==0.33
Flask-Script==2.0.5
Flask-SocketIO==2.9.2
flask-swagger-ui==0.0.3
Flask-WTF==0.14.2
gevent==1.2.2
greenlet==0.4.12
html5lib==1.0b8
hurry.filesize==0.9
hypchat==0.21
idna==2.6
infinity==1.4
intervals==0.8.0
itsdangerous==0.24
Jinja2==2.9.5
jira==1.0.10
lazy-object-proxy==1.2.2
lxml==3.8.0
MarkupSafe==1.0
monotonic==1.4
oauthlib==2.0.2
olefile==0.44
ordereddict==1.1
packaging==16.8
pbr==3.0.1
pdfkit==0.6.1
Pillow==4.0.0
pql==0.4.3
psutil==5.4.1
py==1.4.34
pymongo==3.4.0
pyodbc==4.0.15
pyparsing==2.2.0
PyPDF2==1.26.0
pypyodbc==1.3.4
python-dateutil==2.6.0
python-engineio==2.0.1
python-memcached==1.58
python-socketio==1.8.3
pytz==2016.10
reportlab==3.4.0
requests==2.13.0
requests-oauthlib==0.8.0
requests-toolbelt==0.8.0
six==1.10.0
SQLAlchemy==1.1.6
SQLAlchemy-Utils==0.32.14
suds==0.4
urllib3==1.22
validators==0.11.3
vine==1.1.3
webencodings==0.5.1
Werkzeug==0.12
wrapt==1.10.10
WTForms==2.1
xmltodict==0.10.2
WTForms-Components==0.10.3

关于以下情况,我感到很红: - 猴子补丁Gevent - 通过uwsgi的早期猴子补丁Gevent(假设在uWSGI 2.1上工作) - 添加Redis队列

还有其他方法可以让Flask-SocketIO与uWSGI worker同步工作吗?

2 个答案:

答案 0 :(得分:1)

这似乎是redis的一个问题 你安装并启动它吗? 跑 redis-cli -h localhost -p 6379 确保flask-socketIO可以连接到它

答案 1 :(得分:0)

@shalbafzadeh给了我一个惊人的领先优势。这是答案:

uWSGI多工作模式中的Flask-SocketIO需要使用monkey-patchin和某些消息队列机制,如文档中所述,如Redis。使Redis工作,解决了描述的问题。 Redis部分来了:

<强>&安培; TL; DN Redis连接字符串无效。 Redis不支持url中的特殊字符,甚至编码。

Flask-SocketIO需要连接字符串到redis(代码隐藏使用redis.Redis.from_url()方法)。我在发布问题时明确错误,跳过了我的redis受密码保护的事实,所以url实际上看起来如下:

  

&#39; redis的:// [:#RedIsPass] @localhost:一分之六千三百七十九&#39;

然而,由于密码字符串的规范化并将其作为主机加载,错误消息会略有误导。它删除了特殊的字符和小写的一切。这给我带来了错误信息:

  

错误-2连接到redispass:6379。名称或服务未知。

当我将连接字符串修复为:

  

&#39; redis的://:RedIsPass#@本地:一分之六千三百七十九&#39;

我遇到了另一个问题,这次&#34;无效的IPV6&#34;错误。 它是由密码中的#引起的。遗憾的是,Redis lib没有URL解码,所以即使用%23替换#也不会解决问题,因为%23作为纯文本传递并且与密码不匹配。不得不在服务器上更改密码。 常规密码完成了这项工作。