Gevent/Gevent-websocket not being used by Flask-SocketIO - python

I am building a web interface/data API using Flask and Flask-SocketIO for websocket communication. I would like to start shifting to a more development-ready setup using Gevent/Gevent-websocket, Gunicorn, and eventually Nginx for load balancing. However, after installing Gevent and Gevent-websocket, I am still getting a warning message when starting the SocketIO server:
WebSocket transport not available. Install eventlet or gevent and gevent-websocket for improved performance.
According to the Flask-SocketIO docs,
When the application is in debug mode the Werkzeug development server is still used and configured properly inside socketio.run(). In production mode the eventlet web server is used if available, else the gevent web server is used. If eventlet and gevent are not installed, the Werkzeug development web server is used.
This implies that the use of Gevent should be automated behind the scenes as part of Flask-SocketIO. I checked my Python installs with pip list and confirmed that I have Gevent 1.3.4 and Gevent-websocket 0.10.1 installed. Here is the initialization code for the SocketIO server:
app.py
flaskApp = Flask(__name__)
flaskApp.config['SESSION_TYPE'] = 'filesystem'
Session(flaskApp)
socketio = SocketIO(flaskApp, async_mode='threading', manage_session=False)
def createApp():
flaskApp.secret_key = "super secret"
socketio.run(flaskApp, host='0.0.0.0', port=80)
start.py
app.register_blueprint(monitor.blueprint)
...
createApp()
Why is Flask-SocketIO not detecting my Gevent install?

The portion of the docs that you quoted refers to the async_mode argument, and how it is set by default. You are setting async_mode='threading', so that disables the automatic selection of an async mode. Remove the argument, and then you'll get eventlet or gevent, depending on what you have installed.

Related

Production Flask-SocketIO + ZeroRPC

I've deployed a flask-socketio web server, but after installing zerorpc which installs gevent i'm facing a lot of troubles..
at first my code looked like this:
socketio.start_background_task(poll_events)
socketio.run(app, host="0.0.0.0", keyfile='key.pem', certfile='cert.pem')
I'm starting a background task which will constantly read from a queue and send messages through socketio. now that gevent is installed it flask-socketio will try to use it (which i'm fine with actually making my server a production server and not a development one) but then socketio.start_background_task blocks. So I read that
from gevent import monkey; monkey.patch_all()
is required.
So now my code looks like that:
socketio.start_background_task(poll_events)
WSGIServer(('0.0.0.0', 5000), app, keyfile='key.pem', certfile='cert.pem').serve_forever()
For some reason when debugging with pycharm I received a lot of weird greenlet exceptions and also I think that sometimes socketio messages are dropped so I decided to use eventlet. Then again, patching is required. So my code looks like this:
socketio.start_background_task(poll_events)
eventlet.wsgi.server(eventlet.wrap_ssl(eventlet.listen(("0.0.0.0", 5000)), keyfile='key.pem', certfile='cert.pem'), app)
Because of monkey patching zerorpc throws an exception
"gevent.exceptions.LoopExit: This operation would block forever"
What is the correct way to deploy a production server with flask + socketio + zerorpc?
I've resolved the issue, when debugging I choose "threading" as async_mode
socketio = SocketIO(app, async_mode="threading")
and when deploying with gunicorn I use gevent
CMD ["gunicorn", "-w", "1", "-k", "gevent","--reload", "web_app:app"]
For some reason gevent doesn't work without gunicorn and eventlet wouldn't work with zerorpc..

Flask disables stardard output when standard output is redirected

I would like to use standard output from my Flask application to communicate status information to other process connected through pipeline, but it turns out that Flask somehow disables standard output when standard output is redirected.
Here is my sample Flask app:
from flask import Flask
app = Flask(__name__)
#app.route('/')
def hello_world():
return 'Hello, World!'
def prepare():
# Do some preparation work
pass
prepare()
print('ready')
Now compare two different but very similar ways of starting this app:
$ FLASK_APP=my_app.py flask run 2>/dev/null
* Serving Flask app "my_app.py"
* Environment: production
WARNING: This is a development server. Do not use it in a production deployment.
Use a production WSGI server instead.
* Debug mode: off
ready
When standard output is redirected, my status message is muted (but application works as evidenced when accessed through web interface):
$ FLASK_APP=my_app.py flask run 2>/dev/null | cat
* Serving Flask app "my_app.py"
* Environment: production
WARNING: This is a development server. Do not use it in a production deployment.
Use a production WSGI server instead.
* Debug mode: off
Does anybody know how to allow standard output messages go through pipeline in Flask app?
I can't use web interface for the purpose because I have a function decorated with #before_first_request and querying for status will trigger it, which I don't want.
Version information:
$ flask --version
Python 3.6.12
Flask 1.1.2
Werkzeug 1.0.1

Deploying Flask Socket.io application with eventlet on heroku

I am using flask socket.io configured with eventlet on a free heroku instance. According to the flask socket.io documentation: https://flask-socketio.readthedocs.io/en/latest/ running socketio.run(app) will start a webserver if eventlet is installed.
I have a local react web app attempting to establish a WebSocket connection with this app engine instance. The web app uses socket.io and initially defaults to polling HTTP requests. These requests all timeout-- I'm unable to establish a web socket connection. I'm not sure what might be causing my issue, whether it is my app engine configuration or my flask socket.io setup.
Here is my initialization code for flask socket.io:
app = Flask(__name__)
socketio = SocketIO(app)
socketio.init_app(app, cors_allowed_origins="*")
..
..
if __name__ == '__main__':
socketio.run(app, debug=True)
Here is my Procfile:
web: python3 server.py
Here is the web app code attempting to set up the connection:
import io from 'socket.io-client'
const socketURL = "<app-engine-instance-url>:5000"
const socket = io.connect(socketURL)
You mentioned Heroku, then switched to App Engine. I assume you still meant Heroku?
The application running on Heroku must honor the $PORT environment variable and put the website on that port. Try this:
socketio.run(app, port=int(os.environ.get('PORT', '5000')))
Then from your client application connect to the Heroku URL for your app.

How to run python websocket on gunicorn

I found this 0 dependency python websocket server from SO: https://gist.github.com/jkp/3136208
I am using gunicorn for my flask app and I wanted to run this websocket server using gunicorn also. In the last few lines of the code it runs the server with:
if __name__ == "__main__":
server = SocketServer.TCPServer(
("localhost", 9999), WebSocketsHandler)
server.serve_forever()
I cannot figure out how to get this websocketserver.py running in gunicorn. This is because one would think you would want gunicorn to run server_forever() as well as the SocketServer.TCPServer(....
Is this possible?
GUnicorn expects a WSGI application (PEP 333) not just a function. Your app has to accept an environ variable and a start_response callback and return an iterator of data (roughly speaking). All the machinery encapsuled by SocketServer.StreamRequestHandler is on gunicorn side. I imagine this is a lot of work to modify this gist to become a WSGI application (But that'll be fun!).
OR, maybe this library will get the job done for you: https://github.com/CMGS/gunicorn-websocket
If you use Flask-Sockets extension, you have a websocket implementation for gunicorn directly in the extension which make it possible to start with the following command line :
gunicorn -k flask_sockets.worker app:app
Though I don't know if that's what you want to do.

I can not connect to https waitress wsgi server

I have tried the tutorial of python pyramid framework but, https connection, no matter how able to waitress.
http://docs.pylonsproject.org/projects/pyramid/en/latest/tutorials/wiki2/installation.html
If you look at the documents of waitress, there is an item called 'url_scheme' in pasteDeploy format. I tried to add the following to development.ini:
# # #
# Wsgi server configuration
# # #
[server: main]
use = egg:waitress#main
host = 0.0.0.0
port = 6543
url_scheme = https
But, it seems to be listening for http connections be performed pserve command.
$ serve development.ini - reload
Starting subprocess with file monitor
Starting server in PID 2757.
serving on http://0.0.0.0:6543
There is no response when accessed by browser in this state.
Application I'm trying to create is expecting a https access, but do you think there is a package needed for something else. Or Do I fundamentally wrong somewhere? I would appreciate the advice of experts.
Environment in fedora19, python 3.3.2. the following packages that are included in the virtualenv:
Chameleon == 2.12
Mako == 0.9.0
MarkupSafe == 0.18
PasteDeploy == 1.5.0
Pygments == 1.6
SQLAlchemy == 0.8.2
WebOb == 1.2.3
coverage == 3.7
nose == 1.3.0
pyramid == 1.4.5
pyramid-debugtoolbar == 1.0.8
pyramid-mako == 0.2
pyramid-tm == 0.7
repoze.lru == 0.6
transaction == 1.4.1
translationstring == 1.1
tutorial == 0.0
venusian == 1.0a8
waitress == 0.8.7
zope.deprecation == 4.0.2
zope.interface == 4.0.5
zope.sqlalchemy == 0.7.3
Please tell us the location of the document would be helpful to me means.
Thank you very much!
Waitress does not actually support decoding https requests. The only way to support https is by putting waitress behind a reverse proxy such as nginx. You then allow nginx to decrypt the request and pass it on to waitress. The problem here is that waitress now thinks it's serving an http request because thats what it sees from nginx. The url_scheme setting is for telling waitress that all requests coming into waitress are actually https, which it can then forward on to the application, which uses that fact to help your application generate urls using the https scheme instead of http.
Hopefully that makes sense but either way it should be clear to you that your https setup is not going to work when no where in your pastes have you actually created a certificate or a private key.

Categories