Hi Miguel,
I have an existing flask application that does a bunch of stuff. I am trying to add a flask-socketio piece in order to stream realtime market data onto a webpage that I receiver from an external source. I am finding it hard to integrate flask-socketio into the existing application. I would appreciate any help. Here are snippets of what I have so far:
A piece of __init__.py
import eventlet
from flask_socketio import SocketIO
import json
def create_app(config_name):
app = Flask(__name__)
app.config.from_object(config[config_name])
config[config_name].init_app(app)
bootstrap.init_app(app)
mail.init_app(app)
moment.init_app(app)
db.init_app(app)
login_manager.init_app(app)
pagedown.init_app(app)
eventlet.monkey_patch()
socketio = SocketIO(app, async_mode='eventlet')
I have this in my manage.py ...
if __name__ == '__main__':
socketio.run(app)
clearly, this is a problem, because socketio is not recognized in manage.py
Because I have instantiated socketio in __init__.py, and it is not available in manage.py
Also, I don't know where to place the server side code that is in your example:
@socketio.on('message')
def handle_message(message):
print('received message: ' + message)
i am thinking this needs to go into the views.py of a typical Flask application.
I am not sure I am articulating my problem correctly.
I am trying to add flask-socketio functionality to an existing flask application.
A lot of this technology is new to me. I am taking your example trying to fashion it to my needs.
Please help.
Thanks in advance.
Neela.
You can import socketio in your manage.py module, so that then you can start the server with socketio.run(app).
If you want some ideas regarding project structure, you may want to take a look at my flack project.
Thank you very much Miguel. Do I need Celery? Your Flack app seems to be integrated with Celery. I currently use Flask with gunicorn and nginx. Haven't used Celery.
Celery is not required for Flask-SocketIO. Flack uses it to run asynchronous tasks, if you don't need that, then ignore that part of the application.
Thank you.
I have a couple of follow up questions .. In order to keep things simple, I tried a standalone approach where I keep the "non socketio Flask" and "socketio Flask" applications separate.
If I launch the socketio Flask application as "python application.py", it runs fine.
The application is setup in the following manner:
import eventlet
from flask_socketio import SocketIO, emit
...
app = Flask(__name__)
app.config['SECRET_KEY'] = 'secret!'
app.config['DEBUG'] = True
socketio = SocketIO(app)
...
if __name__ == '__main__':
socketio.run(app)
If I run the above application in the following manner instead:
gunicorn -b 127.0.0.1:5000 --timeout=1200 application:app
It throws the following error:
Traceback (most recent call last):
File "/home/server/projects/async_flask/async_flask/lib/python2.7/site-packages/gunicorn/workers/sync.py", line 135, in handle
self.handle_request(listener, req, client, addr)
File "/home/server/projects/async_flask/async_flask/lib/python2.7/site-packages/gunicorn/workers/sync.py", line 176, in handle_request
respiter = self.wsgi(environ, resp.start_response)
File "/home/server/projects/async_flask/async_flask/local/lib/python2.7/site-packages/flask/app.py", line 1836, in __call__
return self.wsgi_app(environ, start_response)
File "/home/server/projects/async_flask/async_flask/local/lib/python2.7/site-packages/flask_socketio/__init__.py", line 27, in __call__
raise RuntimeError('You need to use a gevent-socketio server.')
RuntimeError: You need to use a gevent-socketio server.
The second question I have is that I have an nginx sites-available file setup as follows to cover the two flask applications:
server {
listen 80;
access_log /home/server/projects/flasky/logs/nginx/access.log;
error_log /home/server/projects/flasky/logs/nginx/error.log;
location / {
proxy_set_header X-Forward-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
if (!-f $request_filename) {
proxy_pass http://127.0.0.1:8000;
break;
}
}
location /static {
alias /home/server/projects/flasky/app/static/;
autoindex on;
}
}
server {
listen 80;
server_name _;
access_log /home/server/projects/async_flask/logs/nginx/access.log;
error_log /home/server/projects/async_flask/logs/nginx/error.log;
location / {
include proxy_params;
proxy_pass http://127.0.0.1:5000;
}
location /socket.io {
include proxy_params;
proxy_http_version 1.1;
proxy_buffering off;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
proxy_pass http://127.0.0.1:5000/socket.io;
}
}
I can see both applications under 127.0.0.1:8000 and 127.0.0.1:5000 on the local host.
From outside the machine though, I can only see the 127.0.0.1:8000 application.
Would appreciate any help with these two questions.
Thank you.
@neela77777 The documentation explains all the supported options for deploying a Flask-SocketIO application. In particular, gunicorn is only supported when you use it alongside eventlet or gevent, not standalone like you are. See the docs for information and examples.
Also, this message:
RuntimeError: You need to use a gevent-socketio server.
suggests you are using a very old version of Flask-SocketIO. Please upgrade.
Regarding the nginx config, you have two problems. First, you again haven't read the docs on how to deploy Socket.IO with nginx, and second, you seem to have the two applications listening on the same server port, with no specific hostname, so how does the client select which application it wants to send a request to?
My apologies if I came across as not having read the documentation. It is more a case of not understanding the documentation after reading it a few times. But thank you.
Is there a way I can send messages from one html page to another which is being run on two different ports on two different applications?
Flask-SocketIO provides bi-directional communication between each client and its server. If you have two servers, and both use Flask-SocketIO to communicate with its clients, the only piece that Flask-SocketIO does not provide is the communication between the two servers. For this you will need to find your own mechanism, which could be based on a message queue, for example.
Hi, I suppose I could put my question here:
I want to use flask-socketio to handle one or two page in my website, other pages are normal flask project(using HTTP protocol).
I thought it will be weird, In a normal flask project to use socketio.run(app) to run my application.
Is there any good practice I can use as reference?
Please forgive my obsession. ; )
@alfredzhou1902 I don't understand your question. If you don't want to use socketio.run(app), then use flask run, which also works.
@miguelgrinberg
Nice,I got it.Thanks for your patient. :+1:
I had the same question,
I want to use flask-socketio to handle only one page in my website, other pages are normal flask project(using HTTP protocol).
So, while starting the application, should I run socketio.run(app) or normal app.run(), because doing the later results in "RuntimeError('You need to use the gevent-websocket server"
@nitin-sharma5 If you need Socket.IO in your server, then you need to use socketio.run(app). That provides the Socket.IO server, and also includes the support to serve all your HTTP routes.
@miguelgrinberg I just need socketIO in my server for 1 webpage out of the 6 webpages that my application renders. And using socketio.run(app) does not seem to support HTTP routes( maybe it is still trigeering the flask development server, as my other web pages are normal flask project).
also, regarding your app.py example, it gives a runtime error when i replace socketio.run(app) with a normal app.run() ? although the application works fine.
File "/local/openagent/NETCONF-GUI/netconf-gui-5300/venv/lib/python2.7/site-packages/engineio/async_gevent.py", line 34, in __call__
raise RuntimeError('You need to use the gevent-websocket server. '
RuntimeError: You need to use the gevent-websocket server. See the Deployment section of the documentation for more information.
The following are my pip modules. do u notice anything ambiguous?
asn1crypto==0.24.0
atomicwrites==1.2.1
attrs==18.1.0
bcrypt==3.1.4
cffi==1.11.5
click==6.7
cryptography==2.1.4
enum34==1.1.6
Flask==0.12.2
Flask-LDAPConn==0.7.0
Flask-Login==0.4.0
Flask-Session==0.3.1
Flask-SocketIO==3.0.1
Flask-SSE==0.2.1
Flask-WTF==0.14.2
funcsigs==1.0.2
gevent==1.3.6
gevent-websocket==0.10.1
greenlet==0.4.14
idna==2.6
ipaddress==1.0.19
itsdangerous==0.24
Jinja2==2.10
ldap3==2.4.1
lxml==4.1.1
MarkupSafe==1.0
more-itertools==4.3.0
ncclient==0.5.3
paramiko==2.4.0
pathlib2==2.3.2
pluggy==0.7.1
py==1.6.0
pyasn1==0.4.2
pycparser==2.18
PyNaCl==1.2.1
pytest==3.7.4
python-engineio==2.2.0
python-ldap==2.5.2
python-socketio==2.0.0
redis==2.10.6
scandir==1.9.0
six==1.11.0
typing==3.6.6
Werkzeug==0.14.1
WTForms==2.1
xmltodict==0.11.0
It does not matter how many pages use HTTP vs. Socket.IO. If you want Socket.IO to work, you need to start the server via the Socket.IO extension. If none of the actively viewed pages connect over Socket.IO, then no Socket.IO resources will be used.
The HTTP routes should work. If they don't, then make sure the HTTP route functions are imported, because if they are not, they will not be registered with the application.
Most helpful comment
@alfredzhou1902 I don't understand your question. If you don't want to use
socketio.run(app), then useflask run, which also works.