python-3.xgoogle-app-engineplotly-dashgoogle-app-engine-python

Dash app deployed on Google App Engine standard continuously refreshing


I am currently trying to deploy a Python Dash app using App Engine's standard env. When the app is running it will be stable for a few seconds, but then refreshes entirely (i.e. it will flash to a blank loading screen, and then render again).

All user input is lost between refreshes and callbacks are run again. This repeats while the app is running.

The same app behaves normally when run locally, which makes me think it isn't an issue with cyclical callbacks making a feedback loop. Furthermore, there don't appear to be any errors in the GCP app logs.

The contents of app.yaml are:

runtime: python38
instance_class: F4
service: myapp
entrypoint: python app.py
service_account: myproject@appspot.gserviceaccount.com

and the contents of app.py are:

from src.content import app

server = app.server


def run():
    app.run(host="0.0.0.0", port="8080", debug=True)


if __name__ == '__main__':
    run()

The app is deployed by running gcloud app deploy -v myapp_v1 .

Any advice would be welcome.


Solution

  • You're running Dash using the development server, which uses Flask's development server, and which is not intended to be used for Development, so the same holds true for Dash.

    My guess is that this is associated with the hot-reload functionality that is enabled when you run the dev server with debug=True. You could try setting that to False, but even if that works, I'd strongly recommend switching to deploying the app using a WSGI server. It won't take that much extra effort.

    Gunicorn is going to be the easiest. Have a look at the GCP docs outlining how to serve a WSGI app using Gunicorn.

    Looks like it boils down to adding Gunicorn to your requirements.txt and setting the entrypoint param of app.yaml. The Flask instance (and therefore the WSGI entrypoing for your app) is app.server, where app is a dash.Dash instance. I have not done this before, but looking at the GCP docs, my guess at the entrypoint line for you is:

    entrypoint: gunicorn -b :$PORT app:server
    

    The use of if __name__ == '__main__' to run the dev server can then be dropped.