Reputation: 1
[Flask SSE API doesn't work on production]
Hi, i'm facing an issue in my flask application where I have multiple regular APIs and 1 HTTP API that sends SSE to my React app. In my local development env, the app works just fine as expected. However, when I deployed it to CPanel shared hosting, I noticed that the the React app makes proper request of Content-Type text/event-stream, but received text/html response header from the API after 2 minute timeout. Is there anything wrong with how I implemented the server?
main.py
from myapplication import create_app
from flask import stream_with_context
from gevent import monkey; monkey.patch_all()
from gevent.pywsgi import WSGIServer
app = create_app()
if __name__ == '__main__':
http_server = WSGIServer(("localhost", 5000), app)
http_server.serve_forever()
myapplication/init.py
from flask import Flask
from flask_cors import CORS
from flask_sqlalchemy import SQLAlchemy
from os import path, environ
from dotenv import load_dotenv
db = SQLAlchemy()
DATABASE_NAME = 'database.db'
load_dotenv()
def get_database_uri():
host = environ['DB_HOST']
port = environ['DB_PORT']
name = environ['DB_NAME']
username = environ['DB_USER']
password = environ['DB_PASS']
return f'postgresql+psycopg2://{username}:{password}@{host}:{port}/{name}'
def create_database(app):
if not path.exists('myapplication/' + DATABASE_NAME):
db.create_all(app=app)
print('Database created.')
def create_app():
app = Flask(__name__)
CORS(app)
cors = CORS(app, resource = {
r"/*": {
"origins": "*"
}
})
app.config['SECRET_KEY'] = environ['SECRET_KEY']
app.config['SQLALCHEMY_DATABASE_URI'] = get_database_uri()
db.init_app(app)
from .gallery import gallery
from .document import document
from .timer import timer
from .member import member
app.register_blueprint(gallery, url_prefix='/gallery')
app.register_blueprint(document, url_prefix='/document')
app.register_blueprint(timer, url_prefix='/timer')
app.register_blueprint(member, url_prefix='/member')
from .models import Member, Gallery, Document, Timer
create_database(app)
return app
timer.py (SSE api)
global_count = '60'
global_refresh_count = '0'
@timer.route('/stream')
def get_current_stream():
def send_event():
while True:
event_payload = '{"count": "%s", "refreshCount": "%s"}'%(global_count, global_refresh_count)
data_message = f'data: {str(event_payload)}\n\n'
yield data_message
time.sleep(1)
return Response(send_event(), mimetype='text/event-stream')
Local development response: dev response Local development eventstream response: dev event stream response
Production response: prod response
CPanel python app setup:
Application startup file: passenger_wsgi.py
Application Entry point: application
passenger_wsgi.py
import imp
import os
import sys
sys.path.insert(0, os.path.dirname(__file__))
wsgi = imp.load_source('wsgi', 'main.py')
application = wsgi.app
Please kindly help guide me folks, much appreciated!
Upvotes: 0
Views: 1450
Reputation: 11
you have to set certain headers like below
resp = Response(
send_event(),
mimetype='text/event-stream'
)
resp.headers['X-Accel-Buffering'] = 'no'
resp.headers['Cache-Control'] = 'no-cache'
return resp
and configure setting throughout your service
for example in case of nginx:
location '/' {
proxy_buffering off;
proxy_cache off;
proxy_read_timeout 12h;
...
proxy_pass {your_route};
}
in case of gunicorn: set timeout param to 0 when you execute it.
/{path_to}/gunicorn --workers {num_workers} --timeout 0 --bind {path} -m 007 {module}:{app_name}
Upvotes: 1