I'm using Gunicorn to deploy my Dash app. After upgrading to Gunicorn 20.0.0, it fails to find my application.
gunicorn --bind=0.0.0.0 --timeout 600 index:app.server
Failed to find application object 'app.server' in 'index'
[INFO] Shutting down: Master
[INFO] Reason: App failed to load.
This issue on Gunicorn's issue tracker seems to be related to the error, but I can't figure out what I'm supposed to do to fix it. How can I make Gunicorn 20 find my app?
index.py
:
import os
from dash.dependencies import Input, Output
import dash_core_components as dcc
import dash_html_components as html
from pages import overview
from webapp import app
app.index_string = open(os.path.join("html", "index.html")).read()
app.layout = html.Div([
dcc.Location(id="url", refresh=False),
html.Div(id="page-content")
])
@app.callback(Output("page-content", "children"), [Input("url", "pathname")])
def display_page(pathname):
if pathname == "/a-service/overview":
return overview.layout
else:
return overview.layout
if __name__ == "__main__":
app.run_server(debug=True, port=8051)
webapp.py
:
import dash
description = "a description"
title = "a title"
creator = "@altf1be"
app = dash.Dash(
__name__,
meta_tags=[
{"name": "viewport", "content": "width=device-width, initial-scale=1"},
{"name": "description", "content": description},
{"name": "twitter:description", "content": description},
{"property": "og:title", "content": description},
{"name": "twitter:creator", "content": creator}
]
)
server = app.server
app.config.suppress_callback_exceptions = True
Gunicorn 20 changed how it parses and loads the application argument. It used to use eval
, which followed attribute access. Now it only does a simple lookup for a single name in the given module. The ability for Gunicorn to understand Python syntax such as attribute access was not documented or intended.
Dash's docs about deployment don't use the syntax you're using though. They say to do the following, which will work for any version of Gunicorn:
webapp.py
:
server = app.server
$ gunicorn webapp:server
You're already adding the server
alias in the webapp
module, but your code layout is a bit off and making things confusing for you. You're ignoring the setup you do in webapp
and using index
as your entry point instead. You're putting everything in separate top-level modules rather than within a package.
If you want to split your app setup from your index views, you should follow the standard Flask pattern of defining the app, then importing the views after that, all within a package.
project/
myapp/
__init__.py
webapp.py
index.py
webapp.py
:
app = dash.Dash(...)
server = app.server
# index imports app, so import it after app is defined to avoid a circular import
from myapp import index
$ gunicorn myapp.webapp:server
you should also import server from webapp.py to index.py and then use regular gunicorn procedure:
gunicorn index:server -b :8000
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With