Heroku flask + socket.io 400 BAD REQUEST - flask

Hello im trying to deploy my flask app on heroku. Im using flask_socketio module and socket.io in version 4.5(i didn't know how to initialize in 2.3.x version - io())
Here's my flask code:
from flask import Flask, render_template, url_for, redirect, session, request, jsonify
from flask_socketio import SocketIO
from flask_cors import CORS
app = Flask(__name__)
CORS(app)
socketio = SocketIO(app)
#secret key etc...
...
#socketio.on('message')
def handle_msg(msg):
socketio.send('Syncing...')
if __name__ == '__main__':
socketio.run(app)
Here's my javascript:
...
export const socket = io();
socket.connect('https://proman-code-cool.herokuapp.com/');
function init() {
...
//live sync
socket.on('message', function(msg) {
console.log(msg);
boardsManager.reloadBoards(userId);
});
}
init();
And what i want is to make real-time sync to other users after adding something. And this is working locally but on heroku ive got all the time similar errors to:
When i've changed my Procfile to web: gunicorn -k eventlet main:app and with installed eventlet 0.30.2 i've got errors like class uri 'eventlet' invalid or not found. I can't find anywhere solution for that.

eventlet==0.30.2 in requirements.txt and python-3.8.13 in runtime.txt did the job!
Procfile: web: gunicorn --worker-class eventlet -w 1 main:app

Related

How to serve Flask app on waitress and socket.io using eventlet server simultaneously?

I'm using waitress server to deploy the flask app for production. I'm also using flask's socketio along with the eventlet server which requires its own app run.
Currently only serving app on waitress:
serve(app, host='0.0.0.0', port=8080)
How do I include the socket.run command for running the socket server?
socketio.run(app)
My code:
This snippet sets up server for the flask socketio on which it is to be run and in the if name part I serve the app on waitress if in prod mode.
app.py
import eventlet
async_mode = None
if async_mode is None:
try:
async_mode = 'eventlet'
except ImportError:
pass
if async_mode is None:
async_mode = 'threading'
print('async_mode is ' + async_mode)
if async_mode == 'eventlet':
eventlet.monkey_patch()
socketio = socketIO(app,cors_allowed_origins='*',async_mode=async_mode)
if __name__=='__main__':
if env_mode=='dev':
app.run(host='0.0.0.0', port=8080)
elif env_mode=='prod':
serve(app, host='0.0.0.0', port=8080)

File upload working when executing flask command but doesn't work using uwsgi

So I have this basic setup:
hello.py
from flask import Flask, request
from os import environ
app = Flask(__name__)
#app.route("/", methods=['POST'])
def hello():
return repr(request.files)
if __name__ == "__main__":
app.run(host='0.0.0.0', port=8080)
wsgi.py
from hello import app
if __name__ == "__main__":
app.run()
Request is HTTP POST from nodejs.
Running flask command...
FLASK_APP="uwsgi.py" PYTHONUNBUFFERED=1 FLASK_ENV=development flask run --port=8080 --host=0.0.0.0
...output is:
ImmutableMultiDict([('file', <FileStorage: 'screenshot.png' ('image/png')>)])
Running uwsgi command...
venv/bin/uwsgi --http 0.0.0.0:8080 --plugin python --wsgi-file uwsgi.py --callable app --master --processes 4 --threads 2
..output is empty dict
ImmutableMultiDict([])

Flask __init__.py structure on Heroku

from .library.routes import library
2022-05-25T11:06:23.522123+00:00 app[web.1]: ImportError: attempted relative import with no known parent package
This is the log shown by heroku, and I encountered this problem again and again and again.
How could I solve this and deploy my site on heroku?
init.py
from flask import Flask
from .library.routes import library
from .chat.routes import chat
from .extensions import db, bcrypt, login, socketio
from .api.library_api import library_api
from .api.chat_api import chat_api
from .models.chat import user
from .user.routes import user_route
from .api.login_api import login_api
from .api.socket_api import socket_api
def create_app():
app = Flask(__name__)
app.secret_key = "Why would I show it to stackoverflow?"
app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///library.sqlite3"
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False
app.config["SQLALCHEMY_BINDS"] = {
'chat': "sqlite:///chat.sqlite3",
"library": "sqlite:///library.sqlite3"
}
db.init_app(app)
bcrypt.init_app(app)
login.init_app(app)
socketio.init_app(app)
login.blueprint_login_views = {
'chat': '/login',
'library': '/login'
}
with app.app_context():
db.create_all()
app.register_blueprint(library)
app.register_blueprint(chat)
app.register_blueprint(library_api)
app.register_blueprint(chat_api)
app.register_blueprint(user_route)
app.register_blueprint(login_api)
app.register_blueprint(socket_api)
return app
Procfile
web: gunicorn __init__:app --log-file=-
web: gunicorn --worker-class eventlet -w 1 __init__:app
This init.py is really hindering my development (especially when it comes to debugging due to it running 1000% slower than using a one big app.py) but I want to keep the blueprint approach for ease of organization

How to start Flask and Flask-SocketIO via the command line flask run

I started with an application that has several webservices defined. I was able to start the application via flask run on the command line. Afterwards, I integrated flask-sckoetio (i.e. I added the lines from flask_socketio import SocketIO, emit and socketio = SocketIO(app)) and now I'm not able anymore to start the server via flask run.
from flask import Flask, request, abort
from flask_socketio import SocketIO, emit
app = Flask(__name__)
socketio = SocketIO(app)
#app.route('/do_sth', methods=['POST'])
def do_sth():
return ""
I get the following message on the console:
* Serving Flask-SocketIO app "webservices.py"
* Forcing debug mode off
WebSocket transport not available. Install eventlet or gevent and gevent-websocket for improved perform
ance.
c:\program files\python36\lib\site-packages\flask_socketio\__init__.py:496: Warning: Silently ignoring
app.run() because the application is run from the flask command line executable. Consider putting app.
run() behind an if __name__ == "__main__" guard to silence this warning.
use_reloader=use_reloader, **kwargs)
So I updated my code to this:
from flask import Flask, request, abort
from flask_socketio import SocketIO, emit
app = Flask(__name__)
socketio = SocketIO(app)
#app.route('/do_sth', methods=['POST'])
def do_sth():
return ""
if __name__ == '__main__':
socketio.run(app)
But I still get the same error message and the server doesn't start. However, if I just execute the script everything works. But why is flask run not possible anymore?
It happens because of variable __name__ is equal to "__main__" only when the file called directly with a command like python file.py. But your file was imported and his __name__ variable is setted to name of a module which import them.
Solution:
Just delete string if __name__ == "__main__":
Did you install eventlet or gevent, which are mentioned in the error message?
They are also listed under requirements in flask-socketIO documentation.
Try installing them first.
After installing one of them, you can just use flask run to start your application.

Gevent pywsgi server used with gunicorn?

I have a flask app setup to use the gevent WSGIServer in my code. I am also running gunicorn on the command line to start the server.
Should I be using WSGI server in the code when also running with gunicorn? Currently looks like this:
from flask import Flask
from gevent.pywsgi import WSGIServer
application = Flask(__name__)
#application.route("/")
def hello():
return "hello"
if __name__ == '__main__':
port = int(os.environ.get('PORT', 5000))
WSGIServer(('', port), application).serve_forever()
On the command line I am running gunicorn like:
gunicorn -w 4 myapp:application
Do I need the WSGIServer in my code, or just run it as application.run() on the default flask server?
According to Standalone WSGI Containers, The gunicorn and gevent.pywsgi are both WSGI Containers, and the gunicorn only reconize the entry named application.
So the code below if __name__ == '__main__': is not useful anymore.
If you want to use gevent,you could do:
gunicorn -k gevent -w 4 myapp:application