Gunicorn: 'Response' object has no attribute 'status_code' in wsgi.py with websockets

Created on 16 Feb 2016  ·  36Comments  ·  Source: benoitc/gunicorn

I start my app using

gunicorn --worker-class eventlet -w 1 server:app --bind="127.0.0.1:5000"

And when using Flack-SocketIO for websockets I often get an error with Gunicorn not returning from a function properly

[2016-01-30 10:20:53 -0800] [7330] [ERROR] Error handling request
Traceback (most recent call last):
  File "/Users/brianclark/Desktop/Projects/HDP/application/api/venv/lib/python2.7/site-packages/gunicorn/workers/async.py", line 52, in handle
    self.handle_request(listener_name, req, client, addr)
  File "/Users/brianclark/Desktop/Projects/HDP/application/api/venv/lib/python2.7/site-packages/gunicorn/workers/async.py", line 114, in handle_request
    resp.close()
  File "/Users/brianclark/Desktop/Projects/HDP/application/api/venv/lib/python2.7/site-packages/gunicorn/http/wsgi.py", line 423, in close
    self.send_headers()
  File "/Users/brianclark/Desktop/Projects/HDP/application/api/venv/lib/python2.7/site-packages/gunicorn/http/wsgi.py", line 316, in send_headers
    tosend = self.default_headers()
  File "/Users/brianclark/Desktop/Projects/HDP/application/api/venv/lib/python2.7/site-packages/gunicorn/http/wsgi.py", line 297, in default_headers
    elif self.should_close():
  File "/Users/brianclark/Desktop/Projects/HDP/application/api/venv/lib/python2.7/site-packages/gunicorn/http/wsgi.py", line 230, in should_close
    if self.status_code < 200 or self.status_code in (204, 304):
AttributeError: 'Response' object has no attribute 'status_code'

Any advice on configurations I could use to fix this or is it a bug?

Feedback Requested Discussion Investigation help wanted

Most helpful comment

@kramer65 i see. i've been waiting this for ages, if anyone has the fix please share with us! thanks!

All 36 comments

@bclark8923 do you have any application that could help to reproduce the issue?

Yup! What would you like me to do?

On Monday, March 28, 2016, Benoit Chesneau [email protected] wrote:

@bclark8923 https://github.com/bclark8923 do you have any application
that could help to reproduce the issue?


You are receiving this because you were mentioned.
Reply to this email directly or view it on GitHub
https://github.com/benoitc/gunicorn/issues/1210#issuecomment-202484667

Thanks,
Brian Clark
(248) 990 5616
www.hdphealth.com

Get to know me on Facebook https://facebook.com/bclark8923 & Twitter
https://twitter.com/blaurenceclark!

@bclark8923 if it can be streamed so eventually i could include some part in a test that would help :)

Also which version of gunicorn are you using?

Yes please! Email me [email protected] and 19.x of some sort can check
soon

On Monday, March 28, 2016, Benoit Chesneau [email protected] wrote:

@bclark8923 https://github.com/bclark8923 if it can be streamed so
eventually i could include some part in a test that would help :)

Also which version of gunicorn are you using?


You are receiving this because you were mentioned.
Reply to this email directly or view it on GitHub
https://github.com/benoitc/gunicorn/issues/1210#issuecomment-202492005

Thanks,
Brian Clark
(248) 990 5616
www.hdphealth.com

Get to know me on Facebook https://facebook.com/bclark8923 & Twitter
https://twitter.com/blaurenceclark!

Using version 19.4.5

I'm having the same issue. I'm using gunicorn version 18.0.

Any fix available already?

if anyone have z code to reproduce it thatt would help :)

@benoitc - That makes sense.. ;-)

I'll fix something up next week and let you know!

@benoitc - Alright, I fixed something up before the weekend after all.

You can find the repo with instructions in the readme here: https://github.com/kramer65/gunicorn-error

btw: I'm using gunicorn version 18.0

Probably something needs to return gunicorn.workers.async.ALREADY_HANDLED or gunicorn will try to log the request as soon as the application returns from its WSGI handler. Gunicorn needs to know, instead, that the request is now handled entirely by the application.

Both of the examples in the "examples/websocket" directory return this constant from their WSGI handler.

@benoitc - Does the example to reproduce the error help you with finding the error? Can I be of any other assistance to help this be resolved?

@kramer65 yes I reproduced the error.

So Gunicorn is a pure WSGI engine and is expecting a WSGI response containing a status:
https://github.com/benoitc/gunicorn/blob/master/gunicorn/http/wsgi.py#L242

(related to this code: https://github.com/benoitc/gunicorn/blob/master/gunicorn/workers/async.py#L103-L119)

As @tilgovi said you can bypass the response handling from gunicorn by returning ALREADY_HANDLED

As far as I read the code of flash socketio it is wrapping the flask application in socketio.Middleware which itself inheit from engineio.middleware.Middleware:
https://github.com/miguelgrinberg/python-engineio/blob/master/engineio/middleware.py

which return the wsgi application or their own own handler if it find the path:
https://github.com/miguelgrinberg/python-engineio/blob/master/engineio/middleware.py#L45-L52

So it return socketio.Server.handle_request on the websocket path:
https://github.com/miguelgrinberg/Flask-SocketIO/blob/master/flask_socketio/__init__.py#L144

which itself return engineio.Server.handle_request (lot of circular deps in this project...):
https://github.com/miguelgrinberg/python-engineio/blob/master/engineio/server.py#L184

At this point it appears that neither socket.handle_get_request or socket. handle_post_request set the status:
https://github.com/miguelgrinberg/python-engineio/blob/master/engineio/socket.py#L69-L96

And then an error may happen here:
https://github.com/miguelgrinberg/python-engineio/blob/master/engineio/server.py#L251-L252

since it can return a response without having set a status or anything. I can see that the upgrade use the same websocket object as in our example:
https://github.com/benoitc/gunicorn/blob/master/examples/websocket/websocket.py

I think that instead of returning the final r here:
https://github.com/miguelgrinberg/python-engineio/blob/master/engineio/server.py#L251-L252

It should probably return ALREADY_HANDLED like there:
https://github.com/benoitc/gunicorn/blob/master/examples/websocket/websocket.py#L115

Just a guess anyway since that code is quite difficult to read. Hopefully it will helps.

@kramer65 let me know about the status of this ticket for you anyway :)

@benoitc the ALREADY_HANDLED constant is specific to gunicorn. Eventlet has its own version of this constant, defined in a different way: https://github.com/eventlet/eventlet/blob/2cd5f1d9aea53efb4526e7185017bdcc84732588/eventlet/wsgi.py#L69.

The r value that you were following through the code returns evenlet's ALREADY_HANDLED when the websocket connection ends. This is handled automatically by eventlet: https://github.com/eventlet/eventlet/blob/2cd5f1d9aea53efb4526e7185017bdcc84732588/eventlet/websocket.py#L135.

Gunicorn should (I think) recognize eventlet's ALREADY_HANDLED constant in addition to its own and handle it in the same way. I think that will address this problem.

It's great if you can fix this issue. I'm running flask-socketio & gunicorn on my production and don't want to lost data.

I am experiencing similar problems, and was wondering if there is any news on this issue?

@benoitc - Do you think the suggestion as made by @miguelgrinberg above (to let Gunicorn recognize eventlet's ALREADY_HANDLED constant in addition to its own and handle it in the same way) is a good idea?

@kramer65 if you can find a way to cleanly add support for that, I think it makes sense for the eventlet worker to handle it.

Right now the logic to handle this is a bit buried inside gunicorn.workers.async.AsyncWorker#handle_request but maybe that could be handled with indirection via static property that the eventlet worker can override, or by calling an instance method to check already handled by any worker-specific logic that might exist, with the base class doing as it does now.

@tilgovi - It has been a while since you send me your message, but I wanted to respond to this after all. The problem is that I kinda hit my limit in what I can do for this. I really have no clue how to proceed to solve this.

In the meantime my logs are filled with error messages like the one below, so I do have every reason to put some energy in having this solved. I just don't fully understand what the exact cause of the problem is, let alone that I understand how I could solve this.

If anybody wants to get into contact I would be happy to discuss the issue, and then I might be able to be of a bit more help than I am now.

2016-08-23 08:07:16 [2185] [ERROR] Error handling request
Traceback (most recent call last):
  File "/var/www/imd/venv/local/lib/python2.7/site-packages/gunicorn/workers/async.py", line 45, in handle
    self.handle_request(listener, req, client, addr)
  File "/var/www/imd/venv/local/lib/python2.7/site-packages/gunicorn/workers/async.py", line 102, in handle_request
    resp.close()
  File "/var/www/imd/venv/local/lib/python2.7/site-packages/gunicorn/http/wsgi.py", line 369, in close
    self.send_headers()
  File "/var/www/imd/venv/local/lib/python2.7/site-packages/gunicorn/http/wsgi.py", line 284, in send_headers
    tosend = self.default_headers()
  File "/var/www/imd/venv/local/lib/python2.7/site-packages/gunicorn/http/wsgi.py", line 265, in default_headers
    elif self.should_close():
  File "/var/www/imd/venv/local/lib/python2.7/site-packages/gunicorn/http/wsgi.py", line 198, in should_close
    if self.status_code < 200 or self.status_code in (204, 304):
AttributeError: 'Response' object has no attribute 'status_code'

did one fixed it ?.....

@qwexvf - Unfortunately I didn't. My logs are still filling up with errors. :-(

Anybody else?

@kramer65 i see. i've been waiting this for ages, if anyone has the fix please share with us! thanks!

any updates?

I'm sure there are cleaner ways to fix this, but at least it's a start.

@stefaang thanks im gonna try thought it!

When will the fix for this be released on PyPI?

tomorrow
On Fri, 17 Feb 2017 at 16:46, Eddie notifications@github.com wrote:

When will the fix for this be released on PyPI?


You are receiving this because you modified the open/close state.

Reply to this email directly, view it on GitHub
https://github.com/benoitc/gunicorn/issues/1210#issuecomment-280685264,
or mute the thread
https://github.com/notifications/unsubscribe-auth/AAA4ogTRMF7EfR25G6gLrktOdh_iA4Ciks5rdcDYgaJpZM4HbcdP
.

Has it been released?

@benoitc any word on the update being pushed to pypi?

@defionscode i will make a release in on thursday morning (tomorrow).

Excellent, thank you
On Wed, Feb 22, 2017 at 11:54 AM Benoit Chesneau notifications@github.com
wrote:

@defionscode https://github.com/defionscode i will make a release in on
thursday morning (tomorrow).


You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
https://github.com/benoitc/gunicorn/issues/1210#issuecomment-281729992,
or mute the thread
https://github.com/notifications/unsubscribe-auth/AEcrYp6QfVpWXhG14f4M-lPDHMn0cFncks5rfGhWgaJpZM4HbcdP
.

Has this fix been released?

@Decker108 status is tracked by https://github.com/benoitc/gunicorn/issues/1471 . It will be released today...

This bug is still happening on my side with the latest version 19 and 20 of gunicorn. Was it supposed to be fixed @benoitc ?

Was this page helpful?
0 / 5 - 0 ratings