2016-03-10 4 views
2

J'essaie de mettre en place un simple serveur Flask/socketio/eventlet qui s'abonne aux événements Redis. Le comportement que je vois est que lorsque le débogage de Flask est activé, chaque fois que Werkzeug détecte des changements et redémarre socketio, un autre de mes écouteurs redis est démarré (sauf que l'ancien écouteur ne quitte pas).Flask plugio debug avec eventlet et Redis engendre des greenthreads supplémentaires?

est ici une version de travail avec tous les gestionnaires socketio enlevé:

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() 

Throw dans une édition manuelle Redis-cli (PUBLIER msg himom) Ceci produit la sortie suivante:

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'} 

Pourquoi l'écouteur Redis se lance-t-il plusieurs fois? Si je fais des changements et les sauvegarde, Werkzeug en lancera un autre à chaque fois. Comment puis-je gérer cela correctement?

Voici une liste des paquets concernés et leurs versions:

  • Python 2.7.6
  • Flask 0.10.1
  • Werkzeug 0.11.4
  • eventlet 0.18.4
  • Greenlet 0.4.9
  • Flask-Redis 0.1.0
  • Flask-SocketIO 2.2

** MISE À JOUR ** J'ai maintenant une solution partielle. Tout reste au-dessus même, à l'exception du comportement de la piscine a été déplacé dans la fonction « before_first_request » de Flask:

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() 

La question restante est que « before_first_request » ne gère pas le cas où il y a des websockets existants, mais est un question séparée.

+0

Si vous regardez votre liste de processus, obtenez une liste croissante de processus Python pendant que le reloader continue à redémarrer votre serveur? Je pense que cela pourrait être causé par un bogue dans un eventlet qui ne permet pas à un processus parent de tuer l'enfant. – Miguel

+0

Veuillez fournir des versions pour OS, Python, eventlet, werkzeug, flask, socketio. – temoto

+0

J'ai ajouté des versions, @temoto. Je crois qu'ils sont tous les derniers. –

Répondre

1

La solution ici est de mettre mon filetage dans une fonction appelée par Flask:

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

Ce fils supplémentaires résolu à gauche derrière le redémarrage Werkzeug.

1

Ajouter simplement print(os.getpid()) et observer ps aux. Vous devriez remarquer qu'il existe deux processus Python. Changez DEBUG=False, et le "problème" ne se reproduit pas, il y a aussi un processus Python maintenant.

Le problème est que votre code crée redisReader, qu'il s'agisse d'un "gestionnaire de travailleurs" ou d'un processus de "gestionnaire de requêtes". Donc, ne créez pas et ne commencez pas cela pool inconditionnellement. Consultez la documentation Werkzeug où se trouve votre événement "application init", et commencez seulement ici redisReader.

+0

Cela se rapproche d'une solution, mais je ne suis pas à 100%. J'ai pu ajouter mon lecteur redis à la fonction 'before_first_request' et cela fonctionne. Sur le rechargement de werkzeug, un seul thread redis est démarré/réapparu. Le problème est maintenant le front-end a besoin d'un rafraîchissement pour déclencher cette «première demande» pour réactiver le thread. La websocket existante reste allumée mais ne fonctionnera pas jusqu'à ce qu'une demande soit faite ... –

+0

Je devrais également mentionner que je peux tirer la «première demande» d'un autre onglet de navigateur Web et que les choses commencent à fonctionner de nouveau pour l'étiquette originale. –

+0

Je ne comprends pas le nouveau problème. Si le problème d'origine est résolu, fermez-le et créez une nouvelle question avec les détails et les étapes à reproduire. Si le problème persiste, veuillez mettre à jour la question avec les détails. – temoto