-
Notifications
You must be signed in to change notification settings - Fork 1.8k
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
Gunicorn worker closes the connection instead of returning 500 error. #1507
Comments
i had the same issue INFO:sqlalchemy.engine.base.Engine:{'hubot_id_1': 249} |
The problem here is that Gunicorn sees the exception bubble out of your handler and thinks it's a socket error on the client side. Gunicorn already has code in place to try to send an error message to a client, and to log a message when that fails. It also has code to ignore cases that seem like client disconnects. It also knows how to log the request URI that cause an exception. I think the following should be a safe change we can make that might fix this issue: diff --git a/gunicorn/workers/async.py b/gunicorn/workers/async.py
index a3a0f91..ac4998b 100644
--- a/gunicorn/workers/async.py
+++ b/gunicorn/workers/async.py
@@ -75,7 +75,7 @@ class AsyncWorker(base.Worker):
self.handle_error(req, client, addr, e)
except EnvironmentError as e:
if e.errno not in (errno.EPIPE, errno.ECONNRESET):
- self.log.exception("Socket error processing request.")
+ self.handle_error(req, client, addr, e)
else:
if e.errno == errno.ECONNRESET:
self.log.debug("Ignoring connection reset")
diff --git a/gunicorn/workers/sync.py b/gunicorn/workers/sync.py
index 1d2ce2f..020bcf0 100644
--- a/gunicorn/workers/sync.py
+++ b/gunicorn/workers/sync.py
@@ -146,7 +146,7 @@ class SyncWorker(base.Worker):
self.handle_error(req, client, addr, e)
except EnvironmentError as e:
if e.errno not in (errno.EPIPE, errno.ECONNRESET):
- self.log.exception("Socket error processing request.")
+ self.handle_error(req, client, addr, e)
else:
if e.errno == errno.ECONNRESET:
self.log.debug("Ignoring connection reset") |
The bug here appears to be that Gunicorn is seeing an upstream disconnection and thinking it's a downstream (client) disconnect, and therefore not trying to send a response. |
maybe there is a better way to distinguish our errors from the application error?. If we only catch our own isssues then any application errors could indeed trigger that handler. Thoughts? |
Hey @tilgovi @benoitc I am experiencing somewhat similar issue. As seen, gunicorn ignores the connection reset, but doesn't send the response. I receive the following in curl output: |
Requests should probably also handle its own exceptions. Is there any ticket for it? On our side I wonder if we could be more granular in the way we are catching our own exceptions by wrapping all sockets and other usage related to our calls. The general idea is to distinct the app errors from ours. Thoughts? |
Any updates/workaround for that? |
I didn't have any news from the Request project ;) Anyway I will have a closer look when the merge of Python 3 changes will be done sometimes this month. |
Actually I don't think it should be handled on Request project side. Here a simple Gunicorn app file
Any exception based on |
well what I meant is tthat to handle it we need to know from where the error is coming. The fact that requests don’t identify its own errors by just letting the socket exception from python oblige us to find a way to track what come from our sockets vs sockets used by the application and requests. Next version will improve it. |
I think this issue can be solved by my patch. Here's a new version that applies to both sync and async worker base classes: --- a/gunicorn/workers/base_async.py
+++ b/gunicorn/workers/base_async.py
@@ -81,6 +81,7 @@ class AsyncWorker(base.Worker):
self.log.debug("Ignoring connection reset")
else:
self.log.debug("Ignoring EPIPE")
+ self.handle_error(req, client, addr, e)
except Exception as e:
self.handle_error(req, client, addr, e)
finally:
diff --git a/gunicorn/workers/sync.py b/gunicorn/workers/sync.py
index 1d2ce2f..14df4da 100644
--- a/gunicorn/workers/sync.py
+++ b/gunicorn/workers/sync.py
@@ -152,6 +152,7 @@ class SyncWorker(base.Worker):
self.log.debug("Ignoring connection reset")
else:
self.log.debug("Ignoring EPIPE")
+ self.handle_error(req, client, addr, e)
except Exception as e:
self.handle_error(req, client, addr, e)
finally: It's not necessary to distinguish errors with the client socket from errors caused by the application code. Regardless of the cause, |
(edited my previous comment, because I had other changes to examples code in the diff) |
I seem to be hitting this issue as well. I get it with empty = []
next(item for item in empty)
|
Same issue on our end. We got some weird issue where our nginx returns hundreds of 502 errors for several seconds once in a while. We eventually tracked it down to gunicorn workers closing the connection when some crashes were not caught in our code and propagated outside of our code. We are using gunicorn 19.7.0 on production. |
Based on diff by @tilgovi: benoitc#1507 (comment)
Based on diff by @tilgovi: benoitc#1507 (comment)
no activity since awhile. closing feel free to create a new ticket if needed. |
I ran into an issue where Gunicorn closes connection without returning http response code when my code encounters an error from requests library.
Running this app:
I try
curl localhost:8000
and get "curl: (52) Empty reply from server", instead of the expected "Internal Server Error" html.The text was updated successfully, but these errors were encountered: