Change Request timeout process
This add a request timeout exception. It cancels task, when request is timeout.
This commit is contained in:
parent
fc19f2ea34
commit
c01cbb3a8c
21
examples/request_timeout.py
Normal file
21
examples/request_timeout.py
Normal file
|
@ -0,0 +1,21 @@
|
|||
from sanic import Sanic
|
||||
import asyncio
|
||||
from sanic.response import text
|
||||
from sanic.config import Config
|
||||
from sanic.exceptions import RequestTimeout
|
||||
|
||||
Config.REQUEST_TIMEOUT = 1
|
||||
app = Sanic(__name__)
|
||||
|
||||
|
||||
@app.route("/")
|
||||
async def test(request):
|
||||
await asyncio.sleep(3)
|
||||
return text('Hello, world!')
|
||||
|
||||
|
||||
@app.exception(RequestTimeout)
|
||||
def timeout(request, exception):
|
||||
return text('RequestTimeout from error_handler.')
|
||||
|
||||
app.run(host="0.0.0.0", port=8000)
|
|
@ -30,6 +30,10 @@ class FileNotFound(NotFound):
|
|||
self.relative_url = relative_url
|
||||
|
||||
|
||||
class RequestTimeout(SanicException):
|
||||
status_code = 408
|
||||
|
||||
|
||||
class Handler:
|
||||
handlers = None
|
||||
|
||||
|
|
|
@ -250,6 +250,7 @@ class Sanic:
|
|||
'sock': sock,
|
||||
'debug': debug,
|
||||
'request_handler': self.handle_request,
|
||||
'error_handler': self.error_handler,
|
||||
'request_timeout': self.config.REQUEST_TIMEOUT,
|
||||
'request_max_size': self.config.REQUEST_MAX_SIZE,
|
||||
'loop': loop
|
||||
|
|
|
@ -13,6 +13,8 @@ except ImportError:
|
|||
|
||||
from .log import log
|
||||
from .request import Request
|
||||
from .response import HTTPResponse
|
||||
from .exceptions import RequestTimeout
|
||||
|
||||
|
||||
class Signal:
|
||||
|
@ -33,8 +35,8 @@ class HttpProtocol(asyncio.Protocol):
|
|||
# connection management
|
||||
'_total_request_size', '_timeout_handler', '_last_communication_time')
|
||||
|
||||
def __init__(self, *, loop, request_handler, signal=Signal(),
|
||||
connections={}, request_timeout=60,
|
||||
def __init__(self, *, loop, request_handler, error_handler,
|
||||
signal=Signal(), connections={}, request_timeout=60,
|
||||
request_max_size=None):
|
||||
self.loop = loop
|
||||
self.transport = None
|
||||
|
@ -45,11 +47,13 @@ class HttpProtocol(asyncio.Protocol):
|
|||
self.signal = signal
|
||||
self.connections = connections
|
||||
self.request_handler = request_handler
|
||||
self.error_handler = error_handler
|
||||
self.request_timeout = request_timeout
|
||||
self.request_max_size = request_max_size
|
||||
self._total_request_size = 0
|
||||
self._timeout_handler = None
|
||||
self._last_request_time = None
|
||||
self._request_handler_task = None
|
||||
|
||||
# -------------------------------------------- #
|
||||
# Connection
|
||||
|
@ -75,7 +79,17 @@ class HttpProtocol(asyncio.Protocol):
|
|||
self._timeout_handler = \
|
||||
self.loop.call_later(time_left, self.connection_timeout)
|
||||
else:
|
||||
self.bail_out("Request timed out, connection closed")
|
||||
self._request_handler_task.cancel()
|
||||
try:
|
||||
response = self.error_handler.response(
|
||||
self.request, RequestTimeout('Request Timeout'))
|
||||
except Exception as e:
|
||||
response = HTTPResponse(
|
||||
'Request Timeout', RequestTimeout.status_code)
|
||||
self.transport.write(
|
||||
response.output(
|
||||
self.request.version, False, self.request_timeout))
|
||||
self.transport.close()
|
||||
|
||||
# -------------------------------------------- #
|
||||
# Parsing
|
||||
|
@ -132,7 +146,7 @@ class HttpProtocol(asyncio.Protocol):
|
|||
self.request.body = body
|
||||
|
||||
def on_message_complete(self):
|
||||
self.loop.create_task(
|
||||
self._request_handler_task = self.loop.create_task(
|
||||
self.request_handler(self.request, self.write_response))
|
||||
|
||||
# -------------------------------------------- #
|
||||
|
@ -165,6 +179,7 @@ class HttpProtocol(asyncio.Protocol):
|
|||
self.request = None
|
||||
self.url = None
|
||||
self.headers = None
|
||||
self._request_handler_task = None
|
||||
self._total_request_size = 0
|
||||
|
||||
def close_if_idle(self):
|
||||
|
@ -204,8 +219,8 @@ def trigger_events(events, loop):
|
|||
loop.run_until_complete(result)
|
||||
|
||||
|
||||
def serve(host, port, request_handler, before_start=None, after_start=None,
|
||||
before_stop=None, after_stop=None,
|
||||
def serve(host, port, request_handler, error_handler, before_start=None,
|
||||
after_start=None, before_stop=None, after_stop=None,
|
||||
debug=False, request_timeout=60, sock=None,
|
||||
request_max_size=None, reuse_port=False, loop=None):
|
||||
"""
|
||||
|
@ -240,6 +255,7 @@ def serve(host, port, request_handler, before_start=None, after_start=None,
|
|||
connections=connections,
|
||||
signal=signal,
|
||||
request_handler=request_handler,
|
||||
error_handler=error_handler,
|
||||
request_timeout=request_timeout,
|
||||
request_max_size=request_max_size,
|
||||
), host, port, reuse_port=reuse_port, sock=sock)
|
||||
|
|
40
tests/test_request_timeout.py
Normal file
40
tests/test_request_timeout.py
Normal file
|
@ -0,0 +1,40 @@
|
|||
from sanic import Sanic
|
||||
import asyncio
|
||||
from sanic.response import text
|
||||
from sanic.exceptions import RequestTimeout
|
||||
from sanic.utils import sanic_endpoint_test
|
||||
from sanic.config import Config
|
||||
|
||||
Config.REQUEST_TIMEOUT = 1
|
||||
request_timeout_app = Sanic('test_request_timeout')
|
||||
request_timeout_default_app = Sanic('test_request_timeout_default')
|
||||
|
||||
|
||||
@request_timeout_app.route('/1')
|
||||
async def handler_1(request):
|
||||
await asyncio.sleep(2)
|
||||
return text('OK')
|
||||
|
||||
|
||||
@request_timeout_app.exception(RequestTimeout)
|
||||
def handler_exception(request, exception):
|
||||
return text('Request Timeout from error_handler.', 408)
|
||||
|
||||
|
||||
def test_server_error_request_timeout():
|
||||
request, response = sanic_endpoint_test(request_timeout_app, uri='/1')
|
||||
assert response.status == 408
|
||||
assert response.text == 'Request Timeout from error_handler.'
|
||||
|
||||
|
||||
@request_timeout_default_app.route('/1')
|
||||
async def handler_2(request):
|
||||
await asyncio.sleep(2)
|
||||
return text('OK')
|
||||
|
||||
|
||||
def test_default_server_error_request_timeout():
|
||||
request, response = sanic_endpoint_test(
|
||||
request_timeout_default_app, uri='/1')
|
||||
assert response.status == 408
|
||||
assert response.text == 'Error: Request Timeout'
|
Loading…
Reference in New Issue
Block a user