2

Redis イベントをサブスクライブする単純な Flask/socketio/eventlet サーバーをまとめようとしています。私が見ている動作は、Flask デバッグが有効になっていると、Werkzeug が変更を検出して socketio を再起動するたびに、別の 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 msg 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 は毎回別の変更を開始します。これを正しく処理するにはどうすればよいですか?

関連するパッケージとそのバージョンのリストは次のとおりです。

  • パイソン 2.7.6
  • フラスコ 0.10.1
  • Werkzeug 0.11.4
  • イベントレット 0.18.4
  • グリーンレット 0.4.9
  • フラスコ-Redis 0.1.0
  • Flask-SocketIO 2.2

** 更新 ** 現在、部分的な解決策があります。プールの動作が Flask の「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' が既存の websocket がある場合を処理しないことですが、それは別の問題です。

4

2 に答える 2

1

ここでの解決策は、スレッドを Flask によって呼び出される関数に入れることでした。

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

これにより、Werkzeug の再起動時に残された余分なスレッドが解決されました。

于 2016-03-25T18:54:09.080 に答える
1

シンプルを追加print(os.getpid())して観察しps auxます。2 つの Python プロセスがあることに注意してください。変更DEBUG=False,と「問題」は再現されていません。現在、1 つの Python プロセスもあります。

したがって、問題は、redisReaderそれが「ワーカー マネージャー」プロセスであるか、実際の「リクエスト ハンドラー」プロセスであるかに関係なく、コードが作成されることです。したがって、pool無条件に作成して開始しないでください。「アプリケーション初期化」イベントがどこにあるか Werkzeug のドキュメントを参照し、redisReaderそこからのみ開始してください。

于 2016-03-18T23:46:17.610 に答える