Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Gunicorn 20 failed to find application object 'app.server' in 'index'

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
like image 367
Abdelkrim Avatar asked Nov 15 '19 09:11

Abdelkrim


2 Answers

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
like image 162
davidism Avatar answered Sep 28 '22 02:09

davidism


you should also import server from webapp.py to index.py and then use regular gunicorn procedure:

gunicorn index:server -b :8000
like image 32
Ali Halataee Avatar answered Sep 28 '22 03:09

Ali Halataee