Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CORS exception cause gunicorn to not find create_app method #2026

Closed
ghost opened this issue Apr 30, 2019 · 8 comments
Closed

CORS exception cause gunicorn to not find create_app method #2026

ghost opened this issue Apr 30, 2019 · 8 comments

Comments

@ghost
Copy link

ghost commented Apr 30, 2019

Hello,

I observed this issue when using the flask-CORS plugin. The error that shows up is:

...
[2019-04-30 22:42:16 +0000] [9] [INFO] Worker exiting (pid: 9)
Failed to find application object 'create_app()' in 'bug'
[2019-04-30 22:42:16 +0000] [10] [INFO] Worker exiting (pid: 10)
Traceback (most recent call last):
  File "/usr/local/lib/python3.7/site-packages/gunicorn/arbiter.py", line 203, in run
    self.manage_workers()
  File "/usr/local/lib/python3.7/site-packages/gunicorn/arbiter.py", line 545, in manage_workers
...

Note the Failed to find application object 'create_app()' in 'bug' error. create_app() clearly exists.

To reproduce the error do the following:

With the directory structure:

.
├── Dockerfile
├── __init__.py
└── requirements.txt

Dockerfile

FROM python:3.7.3-alpine3.9
WORKDIR /usr/src/app
ADD requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
ADD __init__.py  /usr/src/app/bug/__init__.py
CMD ["gunicorn", "bug:create_app()", "-b", "0.0.0.0:5000", "--workers=4"]

init.py

from flask import Flask
app = Flask(__name__)

@app.route('/')
def index():
    return "Hello world!"

def create_app():
    CORS(app, resources={r"/*": {"origins": "*"}})
    return app

requirements.txt

flask
flask-cors
gunicorn

Run:

docker build -t gunicornbug ./
docker run -d --name gunibug -p 5000:5000 gunicornbug
docker logs gunibug

and you will see the errors I described.

If you remove the CORS line so that __init__.py reads:

from flask import Flask
app = Flask(__name__)

@app.route('/')
def index():
    return "Hello world!"

def create_app():
    return app

and then do another docker build -t gunicornbug ./

The application runs fine when doing curl localhost:5000/

I deliberately didn't include an from flask_cors import CORS at the top to reproduce the error. Not sure what's going on here. This is a dummy example, the project where this error occurred is more complicated so I made a simpler example for reference. Let me know if you need any more info.

@jamadden
Copy link
Collaborator

Are you saying that you'd prefer a different error message? gunicorn currently catches NameError deliberately in order to print a friendly error message --- the idea is that if module:var fails with a NameError on var, it's probably because module doesn't define var. If var() is actually a callable that itself raises NameError, gunicorn has no way to distinguish that.

TIL, actually. I didn't realize gunicorn actually evals the var part of module:var. I assumed it just did getattr(mod, var). But doing that doesn't let someone write var() --- gunicorn can't distinguish a callable that's meant to return the wsgi app from the wsgi app itself...unless it were to try to do some checking of the callable's signature, which seems like a hack.

@ghost
Copy link
Author

ghost commented May 1, 2019

At least with how I interpreted the error message was that var() doesn't exist in module. This (for me) was misleading and I was thinking at first it was a PYTHON_PATH problem or something else. If the eval is failing that would be useful info to know in the error message. For example had it said something similar to:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'CORS' is not defined

that would make more sense. If CORS is in module this error above would (ideally) still show. To illustrate:

module/
├── __init__.py

where __init__.py is :

def create_app():
    CORS

I do:

Patricks-MacBook-Pro:gunicorn-bug pburton$ python3
Python 3.7.3 (default, Mar 27 2019, 09:23:15)
[Clang 10.0.1 (clang-1001.0.46.3)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import module
>>> module.create_app()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Users/pburton/gunicorn-bug/module/__init__.py", line 2, in create_app
    CORS
NameError: name 'CORS' is not defined
>>>

I see that this name doesn't exist within module and it's also a NameError.

@benoitc
Copy link
Owner

benoitc commented May 1, 2019

hrm you run like looks weird. gunicorn should use a wsgi instance and will not use the callback normally. ie it should use the the app from flask

@jamadden
Copy link
Collaborator

jamadden commented May 1, 2019

@benoitc I'm not sure what you mean. Are you saying the module:var() syntax isn't really meant to be used that way? In which case instead of writing bug:create_app(), one should do:

def create_app():
    CORS(app, resources={r"/*": {"origins": "*"}})
    return app
app = create_app()

with bug:app? That pushes the NameError back to import time.

@ghost
Copy link
Author

ghost commented May 1, 2019

Found what appears to be a related issue: #1333

@jamadden
Copy link
Collaborator

jamadden commented May 1, 2019

Yup, the code from that PR is still in place. Enabling debugging for gunicorn will print the original traceback as you requested.

@benoitc
Copy link
Owner

benoitc commented May 1, 2019

@jamadden i am reffering to this line in the docker file : CMD ["gunicorn", "bug:create_app()", "-b", "0.0.0.0:5000", "--workers=4"]

@benoitc
Copy link
Owner

benoitc commented Nov 22, 2019

fixed in latest master

@benoitc benoitc closed this as completed Nov 22, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants