11
votes

Can I use gevent-socketio with Flask, running under Gunicorn, and still enjoy the nice exception printing, debugger, and reload capability that Flask offers? How would my gunicorn worker and WSGI app class look like?

3

3 Answers

11
votes

I've got the exact same problem so I solved it by using watchdog.

pip install watchdog

together with this command:

watchmedo shell-command --patterns="*.py*;;*.less;*.css;*.js;*.txt;*.html" --recursive --command='kill -HUP `cat /tmp/gunicorn.pid` && echo "Reloading code" >> /tmp/gunicorn.log' ~/projectfolder

It requires (well, not really, but I point "Reloading code" into the same logfile so It's a nice thing to have) that you daemonize the gunicorn process, which I do like this:

gunicorn_config.py

workers = 2
worker_class = 'socketio.sgunicorn.GeventSocketIOWorker'
bind = '0.0.0.0:5000'
pidfile = '/tmp/gunicorn.pid'
debug = True
loglevel = 'debug'
errorlog = '/tmp/gunicorn.log'
daemon = True

Start the application:

gunicorn run:app -c gunicorn-config.py

View the log:

tail -f /tmp/gunicorn.log

From this point everything should be reloaded with each change in your project. It's a bit complicated but since gunicorn with a worker (or the built in socketio-server) doesn't have any reloading capabilities I had to do it like this.

It's a different approach compared to the decorator solution in the other answer but I like to keep the actual code clean from development specific solutions. Both accomplish the same thing so I guess you'll just have to pick the solution you like. :)

Oh, as an added bonus you get to use the production server in development which means both environments match each other.

5
votes

I've been looking into this subject lately. I don't think you can easily use autoreload feature with Flask + gevent-socket.io + Gunicorn. Gunicorn is a production server that does not allow such features natively.

However, I found a nice solution for my development server : user SocketIOServer provided with the library and a Flask snippet for autoreload. Here is the startup script (runserver.py) :

from myapp import app
from gevent import monkey
from socketio.server import SocketIOServer
import werkzeug.serving

# necessary for autoreload (at least)
monkey.patch_all()

PORT = 5000

@werkzeug.serving.run_with_reloader
def runServer():
    print 'Listening on %s...' % PORT
    ws = SocketIOServer(('0.0.0.0', PORT), app, resource="socket.io", policy_server=False)
    ws.serve_forever()

runServer()

This solution is inspired from : http://flask.pocoo.org/snippets/34/

3
votes

I've made some tweaks to Werkzeug debugger so it now works with socket.io namespaces, see below and enjoy :)

https://github.com/aldanor/SocketIO-Flask-Debug