WebSocket support without gevent for Flask and other WSGI frameworks.

miguelgrinberg, updated 🕥 2023-02-07 23:26:35

flask-sock

Build status codecov

WebSocket support for Flask. What makes this extension different than others is that it does not require a greenlet based server (gevent, eventlet) to work.

This WebSocket implementation is compatible with the Flask development web server. For a production deployment it can be used with Gunicorn, Eventlet or Gevent.

Resources

Issues

When used with eventlet, exception shown after multiple connections

opened on 2023-03-13 00:38:22 by wmww

The code (minimal example that simply closes websocket connections immediately upon creation): ```python3 import flask import flask_sock import eventlet from eventlet import wsgi

eventlet.monkey_patch()

app = flask.Flask(name) sock = flask_sock.Sock(app)

@sock.route('/websocket') def websocket(ws): ws.close()

if name == 'main': wsgi.server(eventlet.listen(("127.0.0.1", 5055)), app) To test a connection: wscat --connect 'ws://localhost:5055/websocket' It gets disconnected (as we expect), but if you run it again a long error is printed in the Python output: (1572383) wsgi starting up on http://127.0.0.1:5055 (1572383) accepted ('127.0.0.1', 51362) 127.0.0.1 - - [12/Mar/2023 17:33:25] "GET /websocket HTTP/1.1" 200 0 0.001137 (1572383) accepted ('127.0.0.1', 51378) Exception in thread Thread-1 (_thread): Traceback (most recent call last): File "/home/wmww/.local/lib/python3.10/site-packages/eventlet/greenio/base.py", line 364, in _recv_loop self._read_trampoline() File "/home/wmww/.local/lib/python3.10/site-packages/eventlet/greenio/base.py", line 332, in _read_trampoline self._trampoline( File "/home/wmww/.local/lib/python3.10/site-packages/eventlet/greenio/base.py", line 211, in _trampoline return trampoline(fd, read=read, write=write, timeout=timeout, File "/home/wmww/.local/lib/python3.10/site-packages/eventlet/hubs/init.py", line 159, in trampoline return hub.switch() File "/home/wmww/.local/lib/python3.10/site-packages/eventlet/hubs/hub.py", line 313, in switch return self.greenlet.switch() eventlet.hubs.IOClosed: [Errno 107] Operation on closed file

During handling of the above exception, another exception occurred:

Traceback (most recent call last): File "/usr/lib/python3.10/threading.py", line 1016, in _bootstrap_inner self.run() File "/usr/lib/python3.10/threading.py", line 953, in run self._target(self._args, *self._kwargs) File "/home/wmww/.local/lib/python3.10/site-packages/simple_websocket/ws.py", line 160, in _thread in_data = self.sock.recv(self.receive_bytes) File "/home/wmww/.local/lib/python3.10/site-packages/eventlet/greenio/base.py", line 370, in recv return self._recv_loop(self.fd.recv, b'', bufsize, flags) File "/home/wmww/.local/lib/python3.10/site-packages/eventlet/greenio/base.py", line 367, in _recv_loop raise EOFError() EOFError 127.0.0.1 - - [12/Mar/2023 17:33:28] "GET /websocket HTTP/1.1" 200 0 0.000883 ``` What's the cause of this, and can it be prevented or safely ignored?

flask version: 2.2.3 flask-sock version: 0.6.0 eventlet version: 0.33.3

response time slows down after time

opened on 2022-12-08 01:21:03 by acierp

after sometime time, emitting becomes veryyy slow and affects the entire webserver. the only fix i've found to this is restarting after an interval.

Unexpected behavior

opened on 2022-11-25 06:30:28 by Yakabuff

I tried copying your example (https://blog.miguelgrinberg.com/post/add-a-websocket-route-to-your-flask-2-x-application) and it just spams the page with this rendering the entire browser unresponsive. Any idea why? image

flask-sock ssl

opened on 2022-09-15 06:35:39 by zimsekdanilo

How do I deploy flask-scok application with ssl? What changes should be made?

How to extend this to work with uWSGI?

opened on 2022-07-01 00:03:32 by etale-cohomology

Hi, my understanding is that this only works with the Flask dev server, and with gunicorn.

How can one extend this to work with uwsgi too?

I got flask-socketio working with uwsgi (and gevent) doing something like:

uwsgi --module app:app --touch-reload app.py --master --http :8000 --http-websockets --gevent 1024

but (unsurprisingly) the same thing doesn't work with flask-sock, probably because support for uwsgi needs to be specifically implemented. (But how?)

flask-sock in docker-gunicorn environment always returns 404

opened on 2022-05-12 06:43:29 by ch-IAE-HSN

Hi Miguel,

i have an issue with flask-sock in an containerized application. As I tested my app in a local environment, everything works as expected, the javascript in my html-doc connects properly and the communication runs continuously.

But now I switched to an containerized environment using gunicorn as webserver started by supervisor and now the server returns always a 404 as the html doc calls the websocket. I tried several configs to figure out what's happening, but I have no more ideas what to do.

Here are the crucial parts of code, config and log:

app.py ```python ... app = flask.Flask( name, static_folder = '/www/static' )

ws = flask_sock.Sock() ...

def create_app(): ... app.config['SOCK_SERVER_OPTIONS'] = { 'ping_interval' : 5 } ... ws.init_app(app) ... from .views import default ... return app ```

default.py python @ws.route('/api/ws') def wsapi(ws): app.logger.info('ws call') while True: time.sleep(1) ws.send('Hello') app.logger.info('ws cycle')

index.html ```javascript const ws = new WebSocket('ws://'+location.host+'/api/ws');

        ws.addEventListener('open', ev => {
            console.log('WS OPENED!');
        });

        ws.addEventListener('close', ev => {
            console.log('WS CLOSED!');
        });

        ws.addEventListener('message', ev => {
            console.log(ev.data)
        });

```

supervisord.conf ... [program:gunicorn] command=/www/venv/bin/gunicorn wsgi:app -b :80 --reload -k geventwebsocket.gunicorn.workers.GeventWebSocketWorker --workers 4 --threads 100 directory=/www/app user=www-data group=www-data autostart=true autorestart=true stdout_logfile=/dev/stdout stdout_logfile_maxbytes=0 stderr_logfile=/dev/stderr stderr_logfile_maxbytes=0 ...

log (generated with app.before_request & app.after_request) [2022-05-12 08:23:59,915] INFO in app: <Request 'http://10.1.7.3:9500/api/ws' [GET]> [2022-05-12 08:23:59,917] INFO in app: <Response streamed [404 NOT FOUND]>

Maybe you have some hints for me, how to use your flask-extension properly.

Cheers, Carsten

Miguel Grinberg
GitHub Repository