Hello - I've setup your example as is and everything is working but I am confused about the transport being used. I was expecting the transport to be something like /socket.io/?EIO=3&transport=websocket&t=... but instead I see the transport is 'polling' - /socket.io/?EIO=3&transport=polling&t=
Is this expected? Or am I doing something wrong? I am running locally using the code example out of the box and using the latest version of Chrome.
Thank you!
The Socket.IO protocol is based on the concept of transport upgrades. A default connection will always start as long-polling. Only once the two parties are communicating, the client tries to upgrade to WebSocket.
I can't tell if your particular case upgraded to WebSocket or not, but assuming you installed one of the async frameworks that support WebSocket such as eventlet, it is likely it did. You can open the Chrome debugger tools and look in the network tab for the WebSocket request, which would have a response status code of 101 and a status of pending, since it is a long running request. You should also see a bunch of these /socket.io requests, and then once WebSocket is working no more HTTP request traffic. If you see constant requests flying by, then you are still on long-polling.
Thanks Miguel - wow that was a fast response!
I installed eventlet independently and it worked as expected - I am not sure if eventlet==0.21.0 should be added to the example requirements.txt file?
Eventlet is just one of the supported configurations. The standard development server from Flask is also supported as you have seen (though without WebSocket and only for development/testing) and there is also fully supported configurations based on gevent and uWSGI. Many of these configurations can also be used from gunicorn instead of standalone.
The number of options is really large, so I decided not to get involved in the choice of async framework and let users decide by installing their favorite dependencies.
Thanks. That makes sense - I'm actually using gevent in production and locally it works fine. So at least I know my issue is somewhere in my nginx.conf or uwsgi.ini configs somewhere...
Thanks for your help.
So at least I know my issue
Didn't realize you had a specific issue. What is it? The deployment of Socket.IO is in general very tricky, so I hear issues all the time. Maybe I can help.
Thanks Miguel. Yes, I did find this tricky! But I believe I am up and running now. I need to double check but I _think_ I did have to explicitly install gevent-websocket (I am using 0.10.1) - even though I recall reading somewhere that I should not have to. I'll try and redeploy w/o this at some point.
For reference, for anyone else, here are my uwsgi.ini and nginx.conf files. Note that I had to comment out the proxy_pass line - I was getting 400 errors with this in.
Not that it should not make a difference but I am running in Docker on Kubernetes.
Like I said, I believe it is working - I see transport=websocket which is pending, no further polling requests after one initial call, and lots of data streaming!
Thanks for your help and prompt replies!
Sam
Environment:
Client (from package.json):
"socket.io-client": "^2.0.3",
"socketio-wildcard": "^2.0.0"
Server (from requirements.txt):
flask-socketio==2.9.0
gevent==1.2.2
gevent-websocket==0.10.1
uwsgi
[uwsgi]
socket = 127.0.0.1:5000
master = true
processes = 1
module = app:create_app()
memory-report = false
single-interpreter = true
pythonpath = app
http-websockets = true
disable-logging
gevent = 100
gevent-monkey-patch = true
harakiri = 60
nginx.conf
worker_processes 1;
events {
worker_connections 1024;
}
http {
# Configuration containing list of application servers
upstream uwsgi {
server 127.0.0.1:5000;
}
server {
listen 80;
server_name _;
location / {
return 301 https://$host$request_uri;
}
}
# Configuration for Nginx
server {
# Running port
listen 443 ssl;
...
_ssl things commented out_
...
add_header Strict-Transport-Security max-age=15638400;
add_header X-Frame-Options DENY;
add_header X-Content-Type-Options nosniff;
add_header X-K8S-Pod "{{K8S_POD_NAME}}"; # kubernetes pod name
add_header X-Accel-Buffering "no";
proxy_http_version 1.1;
proxy_buffering off;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
# Proxying connections to application servers
location / {
include uwsgi_params;
uwsgi_pass uwsgi;
uwsgi_param Host $host;
uwsgi_param X-Real-IP $remote_addr;
uwsgi_param X-Forwarded-For $proxy_add_x_forwarded_for;
uwsgi_param X-Forwarded-Proto $http_x_forwarded_proto;
uwsgi_buffering off;
# proxy_pass http://127.0.0.1:5000;
}
}
}
@sam-untapt this is interesting, because based on what others have tried, I was under the assumption that uwsgi_pass cannot be used to proxy WebSocket. If you look at the nginx docs, the only place where WebSocket is mentioned is in the proxy module. The way I know some of my users work with uwsgi and nginx is by setting uwsgi in http mode, and using proxy_pass in the nginx config.
@miguelgrinberg
The standard development server from Flask is also supported as you have seen (though without WebSocket and only for development/testing) and there is also fully supported configurations based on gevent and uWSGI.
Its my understanding that configuring the application like below, would override the use of the stock flask development server and instead use eventlet.
# service.py
...
async_mode = "eventlet" ## gevent or eventlet
socketio = SocketIO(app, async_mode=async_mode)
...
if __name__ == "__main__":
socketio.run(app, debug=True)
That being said then, I should simply be able to
$ python service.py
Websockets should be enabled and working when a client connects to that server?
@miguelgrinberg can the development server maintain websockets if eventlet is installed?
@carlcrott I think you are confusing two things. Flask comes with a development server. Flask-SocketIO can use that development server, but normally you would use another server, such as eventlet or gevent. In all cases, however, you can start the server with socketio.run(). In other words, the socketio.run() way of starting the server has really nothing to with the Flask development server, this function can start any of the supported servers.
can the development server maintain websockets if eventlet is installed?
So this question does not really make sense. If eventlet is installed, then you will be using eventlet, not the Flask dev server.
Most helpful comment
Thanks Miguel. Yes, I did find this tricky! But I believe I am up and running now. I need to double check but I _think_ I did have to explicitly install gevent-websocket (I am using 0.10.1) - even though I recall reading somewhere that I should not have to. I'll try and redeploy w/o this at some point.
For reference, for anyone else, here are my uwsgi.ini and nginx.conf files. Note that I had to comment out the proxy_pass line - I was getting 400 errors with this in.
Not that it should not make a difference but I am running in Docker on Kubernetes.
Like I said, I believe it is working - I see transport=websocket which is pending, no further polling requests after one initial call, and lots of data streaming!
Thanks for your help and prompt replies!
Sam
Environment:
Client (from package.json):
"socket.io-client": "^2.0.3",
"socketio-wildcard": "^2.0.0"
Server (from requirements.txt):
flask-socketio==2.9.0
gevent==1.2.2
gevent-websocket==0.10.1
uwsgi
[uwsgi] socket = 127.0.0.1:5000 master = true processes = 1 module = app:create_app() memory-report = false single-interpreter = true pythonpath = app http-websockets = true disable-logging gevent = 100 gevent-monkey-patch = true harakiri = 60nginx.conf
worker_processes 1;
events {
worker_connections 1024;
}
http {
# Configuration containing list of application servers
upstream uwsgi {
server 127.0.0.1:5000;
}
}