Flask-SocketIO needs your help!

Posted by
on under

Some of you know that for the last few weeks I have been quietly but steadily working on a significant new release of Flask-SocketIO that will be labeled 1.0, and that is practically a complete rewrite. Given that this is a fairly popular extension, I would like to ask existing users to test it and provide feedback before it is officially released.

What Is Changing?

A lot of things are changing under the hood in 1.0, and inevitably a few things are also changing in the public interface. However, I expect most existing applications will require little or no changes to run on the 1.0 release.

The big change is in the dependencies. Flask-SocketIO has depended on gevent-socketio to provide the Socket.IO server, and this was problematic because this project hasn't been updated in a long time, forcing users to work with a very old Javascript client. I have dropped gevent-socketio and replaced it with two new packages written by myself, called python-engineio and python-socketio. These packages provide the Socket.IO server-side functionality, now using current versions of the Engine.IO and Socket.IO protocols.

The heavy dependency on gevent has also been removed. In this new version you can choose to use eventlet, gevent or a plain old WSGI web server such as Werkzeug. Out of these three options, eventlet is currently the most complete implementation, with support for the HTTP long-polling and WebSocket transports. The other options only support long-polling at this time.

As a nice side effect of these changes, I can now offer support for Python 3, and since eventlet is very stable on both Python 2 and Python 3, that means that you can use the current Socket.IO client, with the WebSocket transport, on Python 2.7, 3.3 or 3.4.

Here is a more complete list of changes in version 1.0, extracted from the documentation:

  • Release 1.0 drops support for Python 2.6, and adds support for Python 3.3, Python 3.4, and pypy.
  • Releases 0.x required an old version of the Socket.IO Javascript client. Starting with release 1.0, the current releases of Socket.IO are supported (1.3.5 and 1.3.6 have been tested to work).
  • The 0.x releases depended on gevent, gevent-socketio and gevent-websocket. In release 1.0 gevent-socketio and gevent-websocket are not used anymore, and gevent is one of three options for backend web server. The other two options are eventlet, and any regular multi-threaded WSGI server, including Flask's development web server.
  • The Socket.IO server options have changed in release 1.0. They can be provided in the SocketIO constructor, or in the run() call. The options provided in these two are merged before they are used.
  • The 0.x releases exposed the gevent-socketio connection as request.namespace. In release 1.0 this is not available anymore. The request object defines request.namespace as the name of the namespace being handled, and adds request.sid, defined as the unique session ID for the client connection, and request.event, which contains the event name and arguments.
  • To get the list of rooms a client was in the 0.x release required the application to use a private structure of gevent-socketio, with the expression request.namespace.rooms. This is not available in release 1.0, which includes a proper rooms() function.
  • The recommended "trick" to send a message to an individual client was to put each client in a separate room, then address messages to the desired room. This was formalized in release 1.0, where clients are assigned a room automatically when they connect.
  • The 'connect' event for the global namespace did not fire on releases prior to 1.0, due to a problem in gevent-socketio. This has been fixed and now this event fires as expected.
  • Support for client-side callbacks was introduced in release 1.0.

Testers Wanted

If you use Flask-SocketIO, I would appreciate it if you try your application with my current working 1.0 release and provide feedback. I'm particularly interested to find out if you had to make lots of changes to your application to make it work with this version. I made every effort to minimize the changes to the public API, but I did have to make some changes.

How To Install Flask-SocketIO 1.0

I have pushed my current 1.0 version to PyPI as release 1.0a1 (Edit: current version is 1.0b1). Because it is a development version, you have to explicitly request this version to get it:

$ pip install flask-socketio==1.0b1

Or if you are upgrading an existing virtualenv:

$ pip install --upgrade flask-socketio==1.0b1

You can find the example application here: https://github.com/miguelgrinberg/Flask-SocketIO/tree/v1.0/example

If you prefer to install from GitHub, I have pushed this version to the official repository under branch v1.0.

How To Provide Feedback

You can post your comments below, or find me on Twitter or elsewhere. Just contact me in the way that is easier for you.

I appreciate your feedback!

Miguel

Become a Patron!

Hello, and thank you for visiting my blog! If you enjoyed this article, please consider supporting my work on this blog on Patreon!

59 comments
  • #26 Felix said

    No, I wasn't even using gunicorn when I got the error. However, your sample app runs OK, so I guess it must be something in my code base that prevents an upgrade to websockets even though gevent-websocket is imported correctly.

  • #27 carlos said

    Hi Miguel, I have used your last version flask-socketio1.0b1. all works fine for me. Except when I want downgrade it.
    "ImportError: cannot import name socketio_manage
    Exception KeyError: KeyError(140019467738800,) in <module 'threading' from '/usr/lib/python2.7/threading.pyc'> ignored".
    It's say, if I install your last version and then come back to an earlier version. I get this error.

  • #28 Miguel Grinberg said

    @Carlos: the dependencies on the 1.0 and pre-1.0 releases are completely different. To go between these two I recommend that you work with separate virtualenvs.

  • #29 John said

    Miguel,
    Do you think Websockets could replace REST? Do you think that's desirable?

  • #30 Miguel Grinberg said

    @John: There are specific use cases for which WebSocket makes sense. In many (most) cases though, it does not really provide a significant advantage over a regular REST API. The main cases where sockets make sense are those where the clients and server need to exchange short and frequent messages, with minimal latency. A secondary use case is the need for server pushed messages, though this can be emulated with a long-polling API (in fact this extension does exactly that when WebSocket is not available).

  • #31 phil said

    @Miguel: when i read 'Out of these three options, eventlet is currently the most complete implementation, with support for the HTTP long-polling and WebSocket transports. The other options only support long-polling at this time.' i was wodering:
    Were there real websockets with older versions, working with gevent? Or was there only long-polling with eg. v0.6.0 all the time?

  • #32 Miguel Grinberg said

    @phil: yes, release 0.6 uses real WebSocket with gevent. But note that the statement you referenced is outdated. Since this article came out, the project has been expanded. Now there is support for WebSocket in both eventlet and gevent. For gevent you have to also install gevent-websocket.

  • #33 easyrider said

    Hi!

    I am having troubles when executing my flask(socketio) app using gunicorn. I initiate the app the following way:
    sio = SocketIO()
    app = Flask(name)
    app.secret_key('secret')
    sio.init_app(app)

    But when running:
    gunicorn application:sio --worker-class eventlet -w 1

    Error:
    Application object must be callable

    Thanks!

  • #34 Miguel Grinberg said

    @easyrider: use application:app instead of application:sio. Gunicorn needs the Flask application instance.

  • #35 easyrider said

    @Miguel, Thanks, now the application is up and running, but! all socketio-requests gets an 404. It is not possible to connect with socketio..
    I've tried different ways to execute the application like:
    gunicorn --worker-class eventlet application:app -w 1

    And I have also added this to the init.py file:
    sio = SocketIO(app, async_mode='eventlet')

    Any ideas where to start looking?

    (
    my on_connect and on_message is really simple, only printing some debug text. They both works when running the application with sio.run(app....)
    )

    Thanks!

  • #36 Miguel Grinberg said

    @easywriter: are you using version 1.0b4? If not, please upgrade to this beta version and try again.

  • #37 Easyrider said

    Thanks Miguel, it solved my problem.

  • #38 cesco said

    Miguel, Here I am with time to upgrade my app to python 3.
    I am running python 3.4.3 and socketio v1.0b3, could not find 1.0b4 on github.
    Its all working nice, I am trying to user eventlets. It all works but I get these erros sometimes and the users seem to disconnect then reconnect after some time.

    Traceback (most recent call last):
    File "/Users/cesco/Projects/PYTHON/socketio3/venv3/lib/python3.4/site-packages/eventlet/wsgi.py", line 483, in handle_one_response
    write(b''.join(towrite))
    File "/Users/cesco/Projects/PYTHON/socketio3/venv3/lib/python3.4/site-packages/eventlet/wsgi.py", line 426, in write
    _writelines(towrite)
    File "/usr/local/var/pyenv/versions/3.4.3/lib/python3.4/socket.py", line 394, in write
    return self._sock.send(b)
    File "/Users/cesco/Projects/PYTHON/socketio3/venv3/lib/python3.4/site-packages/eventlet/greenio/base.py", line 359, in send
    total_sent += fd.send(data[total_sent:], flags)
    File "/Users/cesco/Projects/PYTHON/socketio3/venv3/lib/python3.4/site-packages/eventlet/greenio/base.py", line 352, in send
    return fd.send(data, flags)
    BrokenPipeError: [Errno 32] Broken pipe

  • #39 Cesco said

    the last comment might be due to the fact I was running it with python instead of gunicorn. Now I am facing often disconects an this stacktrace with gunicorn18.

    2015-11-06 21:29:48 [16828] [ERROR] Error handling request
    Traceback (most recent call last):
    File "/Users/cesco/Projects/power/venv3/lib/python3.4/site-packages/gunicorn/workers/async.py", line 45, in handle
    self.handle_request(listener, req, client, addr)
    File "/Users/cesco/Projects/power/venv3/lib/python3.4/site-packages/gunicorn/workers/async.py", line 102, in handle_request
    resp.close()
    File "/Users/cesco/Projects/power/venv3/lib/python3.4/site-packages/gunicorn/http/wsgi.py", line 369, in close
    self.send_headers()
    File "/Users/cesco/Projects/power/venv3/lib/python3.4/site-packages/gunicorn/http/wsgi.py", line 284, in send_headers
    tosend = self.default_headers()
    File "/Users/cesco/Projects/power/venv3/lib/python3.4/site-packages/gunicorn/http/wsgi.py", line 265, in default_headers
    elif self.should_close():
    File "/Users/cesco/Projects/power/venv3/lib/python3.4/site-packages/gunicorn/http/wsgi.py", line 198, in should_close
    if self.status_code < 200 or self.status_code in (204, 304):
    AttributeError: 'Response' object has no attribute 'status_code'

  • #40 Cesco said

    I am facing another trouble with the app factory pattern.

    On the create_app method:

    from app.socketio import socketiobp as socket_mod
    app.register_blueprint(socket_mod)
    socketioinit.init_app(app, async_mode="eventlet")
    

    on the socketio package (init file):

    socketiobp = Blueprint('socketiobp', name)
    from . import extraController

    on the extraController:

    print("socketinit type:")
    print(type(socketioinit))
    print()
    print("socketinit dir:")
    print(dir(socketioinit))

    @socketioinit.on('my event', namespace='/test')
    .......

    and I get

    socketinit type:
    <class 'flask_socketio.SocketIO'>

    socketinit dir:
    ['class', 'delattr', 'dict', 'dir', 'doc', 'eq', 'format', 'ge', 'getattribute', 'gt', 'hash', 'init', 'le', 'lt', 'module', 'ne', 'new', 'reduce', 'reduce_ex', 'repr', 'setattr', 'sizeof', 'str', 'subclasshook', 'weakref', '_copy_session', 'close_room', 'default_exception_handler', 'emit', 'exception_handlers', 'init_app', 'on', 'on_error', 'on_error_default', 'run', 'send', 'server', 'server_options', 'test_client']

    File "/Users/cesco/Projects/power/app/init.py", line 87, in create_app
    from app.socketio import socketiobp as socket_mod
    File "/Users/cesco/Projects/power/app/socketio/init.py", line 10, in <module>
    from . import extraController
    File "/Users/cesco/Projects/power/app/socketio/extraController.py", line 13, in <module>
    @socketioinit.on('my event', namespace='/test')
    File "/Users/cesco/Projects/power/venv3/lib/python3.4/site-packages/flask_socketio/init.py", line 156, in decorator
    self.server.on(message, _handler, namespace=namespace)
    AttributeError: 'NoneType' object has no attribute 'on'

    Which is SUPER weird!

  • #41 Cesco said

    Just realized I have to init_app() before registering the blueprint otherwise I get that error. Funny thing is that even without errors, the sockets do not work. The only way I got it to work with the app factory pattern is to put all the methods with the @socketio decorator inside my create_app method. Even then I get that Assertion error and Error 32 Broken Pipe sometimes. When it works, I get more longpooling transport the actual websockets.

  • #42 Miguel Grinberg said

    @cesco: Version 1.0 of the extension has been released already, so please get flask_socketio==1.0 from pypi. There was a bug in the beta releases that could have caused these broken pipe errors (which do not cause any problem, they can be ignored really). Try 1.0, and make sure you also upgrade python-socketio and python-engine to their latest versions.

  • #43 Myles said

    Should the latest versions of flask-socketio, python-socketio and python-engineio have fixed the Broken Pipe errors?

    I have updated to latest of all 3 but still getting Broken Pipe errors.

  • #44 Miguel Grinberg said

    @Myles: I'm looking into it, I do get those broken pipe errors in some situations. I'm not sure I can fix them, these are generated by the web server (i.e. eventlet) when the client goes away.

  • #45 Kevin said

    Hi Miguel,

    I have been experimenting with flask-socketio 1.0b4 in Python 3 using a Python client based on the SocketIO-client library (https://pypi.python.org/pypi/socketIO-client) and using the polling mode. From reading your more recent blog posts it sounds possible to run flask-socketio 1.0b4 in a Python 3 app using gevent and gevent-websocket. However, gevent and gevent-websocket are not yet Python 3 compatible (gevent 1.1rc1 is, but gevent-websocket 0.9.5 is not). I'm confused because I think in one of your posts you said you no longer depend on gevent-socketio or gevent-websocket. So is it currently possible to use flask-socketio + gevent + python 3, and if so, how? I actually attempted this using gevent 1.1rc1 and setting async_mode = 'gevent', and the result is various TypeErrors in gevent-websocket because it doesn't follow the Python 3 format for byte strings.

    Thanks,
    Kevin

  • #46 Miguel Grinberg said

    @Kevin: Flask-SocketIO 1.0 has been released already, please upgrade. With Python 3 you can replace all the gevent packages with eventlet, which is very stable under both Python 2 and 3. But also note that while gevent is currently broken for Python 3.5, I believe it works fine for 3.4. And gevent-websocket has also been ported.

  • #47 Mark Sheppard said

    Sounds great. I wrote a socket server in Java some time ago, so I might be able to help out. I'm a Python man these days. Keep up the good work!

  • #48 Kevin said

    Thanks for the info Miguel. The latest version of gevent-websocket is 0.9.5 and they don't support Python 3 yet--there are pending pull requests to add Python 3 support (See: https://bitbucket.org/Jeffrey/gevent-websocket/pull-requests/). You can install the latest gevent-websocket with pip3 but it will crash in Python 3.4 (I've confirmed this with async_mode='gevent'). Unfortunately I have to wait for gevent-websocket to upgrade to Python 3 because eventlet is not compatible with the watchdog library I'm using in my application.

  • #49 Miguel Grinberg said

    @Kevin: wow, you are right, they have not completed the port to Python 3 yet. I was pretty sure I tested this under Python 3 and it worked, but I guess I'm wrong :-)

    In my tests I have found that eventlet works great under Python 3, and it even performs a bit better than gevent-gevent-websocket.

  • #50 Wei said

    Hi Miguel,
    Are you familiar with the flask-sockjs work? how do you compare flask-socket.io to flask-sockjs?
    or more broadly, what's the pros and cons of using socket.io vs using sockjs?
    Thanks.

Leave a Comment