2016-03-10 45 views
2

我正试图组合一个简单的订阅Redis事件的Flask/socketio/eventlet服务器。我看到的行为是,启用Flask调试时,每次Werkzeug检测到更改并重新启动socketio时,我的另一个Redis侦听器也会启动(除了旧侦听程序不会退出)。Flask socks使用eventlet和Redis进行调试会产生额外的绿色线程?

这里有一个工作版本的所有socketio处理程序的删除:

import json 
from flask import Flask, render_template 
from flask_socketio import SocketIO, emit 
from flask.ext.redis import FlaskRedis 
import eventlet 
eventlet.monkey_patch() 

with open('config/flask.json') as f: 
    config_flask = json.load(f) 

app = Flask(__name__, static_folder='public', static_url_path='') 
app.config.update(
     DEBUG= True, 
     PROPAGATE_EXCEPTIONS= True, 
     REDIS_URL= "redis://localhost:6379/0" 
    ) 

redis_cache = FlaskRedis(app) 
socketio = SocketIO(app) 

@app.route('/') 
def index(): 
    cache = {} 
    return render_template('index.html', **cache) 

def redisReader(): 
    print 'Starting Redis subscriber' 
    pubsub = redis_cache.pubsub() 
    pubsub.subscribe('msg') 
    for msg in pubsub.listen(): 
     print '>>>>>', msg 

def runSocket(): 
    print "Starting webserver" 
    socketio.run(app, host='0.0.0.0') 

if __name__ == '__main__': 
    pool = eventlet.GreenPool() 
    pool.spawn(redisReader) 
    pool.spawn(runSocket) 
    pool.waitall() 

扔在一些手动redis的-CLI发布(PUBLISH味精himom) 这将产生以下的输出:

Starting Redis subscriber 
Starting webserver 
* Restarting with stat 
>>>>> {'pattern': None, 'type': 'subscribe', 'channel': 'msg', 'data': 1L} 
Starting Redis subscriber 
Starting webserver 
* Debugger is active! 
* Debugger pin code: 789-323-740 
(22252) wsgi starting up on http://0.0.0.0:5000 
>>>>> {'pattern': None, 'type': 'subscribe', 'channel': 'msg', 'data': 1L} 
>>>>> {'pattern': None, 'type': 'message', 'channel': 'msg', 'data': 'himom'} 
>>>>> {'pattern': None, 'type': 'message', 'channel': 'msg', 'data': 'himom'} 

为什么Redis听众多次入门?如果我进行修改并保存,Werkzeug每次都会启动另一个。我如何正确处理这个问题?

这里所涉及的软件包及其版本的列表:

  • 的Python 2.7.6
  • 瓶0.10.1
  • WERKZEUG 0.11.4
  • eventlet 0.18.4
  • greenlet 0.4.9
  • Flask-Redis 0.1.0
  • Flask-SocketIO 2.2

**更新** 我现在有一个部分解决方案。上述一切都保持不变,除了池的行为已被移动到瓶的“before_first_request”功能:

def setupRedis(): 
    print "setting up redis" 
    pool = eventlet.GreenPool() 
    pool.spawn(redisReader) 

def runSocket(): 
    print "Starting Webserver" 
    socketio.run(app, host='0.0.0.0') 

if __name__ == '__main__': 
    app.before_first_request(setupRedis) 
    print app.before_first_request_funcs 
    runSocket() 

剩下的问题是,“before_first_request”不处理那里有现有的WebSockets的情况,但这是一个单独的问题。

+0

如果你看看你的进程列表,随着重新加载程序不断重启你的服务器,你会得到越来越多的Python进程列表吗?我认为这可能是由于一个不允许父进程杀死孩子的eventlet中的错误引起的。 – Miguel

+0

请提供OS,Python,eventlet,werkzeug,flask,socketio的版本。 – temoto

+0

我已添加版本,@temoto。我相信他们都是最新的。 –

回答

1

解决的办法是把我的穿入由瓶调用的函数:

def setupRedis(): 
    pool = eventlet.GreenPool() 
    pool.spawn(redisReader) 
... 
app.before_first_request(setupRedis) 

这解决了额外的线程上留下WERKZEUG重新启动。

1

添加简单的print(os.getpid())并观察ps aux。您应该注意到有两个Python进程。更改DEBUG=False,并且“问题”不是复制,现在也有一个Python过程。

所以问题是你的代码创建redisReader无论它是“工作管理器”还是实际的“请求处理程序”过程。所以,不要无条件地创建并启动这个pool。请咨询Werkzeug文档,您的“应用程序初始化”事件在哪里,并且仅在那里启动redisReader。这里

+0

这越来越接近解决方案,但我不是100%。我能够将我的redis阅读器添加到'before_first_request'函数中,并且工作正常。在werkzeug的重装上,只有一个redis线程被启动/重新生成。现在的问题是前端需要刷新才能触发“第一次请求”重新启用该线程。现有的websocket保持运行,但是直到发出请求时才会再次运行... –

+0

我还应该提到,我可以从另一个Web浏览器选项卡中触发“第一次请求”,并让原始选项卡再次开始工作。 –

+0

我不明白新问题。如果原始问题已解决,请关闭它并创建新问题,并提供详细信息和重现步骤。如果原始问题仍然存在,请更新问题并提供详细信息。 – temoto

相关问题