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
|
:return: Nothing
|
||||||
"""
|
"""
|
||||||
|
# Define `response` var here to remove warnings about
|
||||||
|
# allocation before assignment below.
|
||||||
|
response = None
|
||||||
|
cancelled = False
|
||||||
try:
|
try:
|
||||||
# -------------------------------------------- #
|
# -------------------------------------------- #
|
||||||
# Request Middleware
|
# Request Middleware
|
||||||
|
@ -597,6 +601,13 @@ class Sanic:
|
||||||
response = handler(request, *args, **kwargs)
|
response = handler(request, *args, **kwargs)
|
||||||
if isawaitable(response):
|
if isawaitable(response):
|
||||||
response = await 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:
|
except Exception as e:
|
||||||
# -------------------------------------------- #
|
# -------------------------------------------- #
|
||||||
# Response Generation Failed
|
# Response Generation Failed
|
||||||
|
@ -622,13 +633,22 @@ class Sanic:
|
||||||
# -------------------------------------------- #
|
# -------------------------------------------- #
|
||||||
# Response Middleware
|
# Response Middleware
|
||||||
# -------------------------------------------- #
|
# -------------------------------------------- #
|
||||||
|
# Don't run response middleware if response is None
|
||||||
|
if response is not None:
|
||||||
try:
|
try:
|
||||||
response = await self._run_response_middleware(request,
|
response = await self._run_response_middleware(request,
|
||||||
response)
|
response)
|
||||||
|
except CancelledError:
|
||||||
|
# Response middleware can timeout too, as above.
|
||||||
|
response = None
|
||||||
|
cancelled = True
|
||||||
except BaseException:
|
except BaseException:
|
||||||
error_logger.exception(
|
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
|
# pass the response to the correct callback
|
||||||
if isinstance(response, StreamingHTTPResponse):
|
if isinstance(response, StreamingHTTPResponse):
|
||||||
|
|
Loading…
Reference in New Issue
Block a user