Modifications the handle_request
function to detect and gracefully handle the case that the request_handler Task is canceled by the sanic server while it is handling the request. One common occurrence of this is when the server issues a ResponseTimeout error, it also cancels the response_handler Task.
The Canceled exception handler purposely sets `response` to `None` to drop references to the handler coroutine, in an attempt to preemptively release resources. This commit also fixes a possible reference-before-assignment of the `response` variable in the `handle_request` function. Finally, another byproduct of this change is that ResponseMiddleware will no longer run if the `response` is `None`.
This commit is contained in:
parent
b238be54a4
commit
39ff02b6e4
22
sanic/app.py
22
sanic/app.py
|
@ -571,6 +571,10 @@ class Sanic:
|
|||
|
||||
:return: Nothing
|
||||
"""
|
||||
# Define `response` var here to remove warnings about
|
||||
# allocation before assignment below.
|
||||
response = None
|
||||
cancelled = False
|
||||
try:
|
||||
# -------------------------------------------- #
|
||||
# Request Middleware
|
||||
|
@ -597,6 +601,13 @@ class Sanic:
|
|||
response = handler(request, *args, **kwargs)
|
||||
if isawaitable(response):
|
||||
response = await response
|
||||
except CancelledError:
|
||||
# If response handler times out, the server handles the error
|
||||
# and cancels the handle_request job.
|
||||
# In this case, the transport is already closed and we cannot
|
||||
# issue a response.
|
||||
response = None
|
||||
cancelled = True
|
||||
except Exception as e:
|
||||
# -------------------------------------------- #
|
||||
# Response Generation Failed
|
||||
|
@ -622,13 +633,22 @@ class Sanic:
|
|||
# -------------------------------------------- #
|
||||
# Response Middleware
|
||||
# -------------------------------------------- #
|
||||
# Don't run response middleware if response is None
|
||||
if response is not None:
|
||||
try:
|
||||
response = await self._run_response_middleware(request,
|
||||
response)
|
||||
except CancelledError:
|
||||
# Response middleware can timeout too, as above.
|
||||
response = None
|
||||
cancelled = True
|
||||
except BaseException:
|
||||
error_logger.exception(
|
||||
'Exception occurred in one of response middleware handlers'
|
||||
'Exception occurred in one of response '
|
||||
'middleware handlers'
|
||||
)
|
||||
if cancelled:
|
||||
raise CancelledError()
|
||||
|
||||
# pass the response to the correct callback
|
||||
if isinstance(response, StreamingHTTPResponse):
|
||||
|
|
Loading…
Reference in New Issue
Block a user