diff --git a/CHANGES/5094.feature b/CHANGES/5094.feature new file mode 100644 index 00000000000..2d140f175e9 --- /dev/null +++ b/CHANGES/5094.feature @@ -0,0 +1 @@ +Add keepalive_timeout parameter to web.run_app. diff --git a/CONTRIBUTORS.txt b/CONTRIBUTORS.txt index 50aefb5826d..7cabbbf12b7 100644 --- a/CONTRIBUTORS.txt +++ b/CONTRIBUTORS.txt @@ -141,6 +141,7 @@ Jaesung Lee Jake Davis Jakob Ackermann Jakub Wilk +Jan Buchar Jashandeep Sohi Jens Steinhauser Jeonghun Lee diff --git a/aiohttp/web.py b/aiohttp/web.py index 66874471e13..75eab48cfe1 100644 --- a/aiohttp/web.py +++ b/aiohttp/web.py @@ -292,6 +292,7 @@ async def _run_app( path: Optional[str] = None, sock: Optional[socket.socket] = None, shutdown_timeout: float = 60.0, + keepalive_timeout: float = 75.0, ssl_context: Optional[SSLContext] = None, print: Optional[Callable[..., None]] = print, backlog: int = 128, @@ -314,6 +315,7 @@ async def _run_app( access_log_class=access_log_class, access_log_format=access_log_format, access_log=access_log, + keepalive_timeout=keepalive_timeout, ) await runner.setup() @@ -466,6 +468,7 @@ def run_app( path: Optional[str] = None, sock: Optional[socket.socket] = None, shutdown_timeout: float = 60.0, + keepalive_timeout: float = 75.0, ssl_context: Optional[SSLContext] = None, print: Optional[Callable[..., None]] = print, backlog: int = 128, @@ -496,6 +499,7 @@ def run_app( path=path, sock=sock, shutdown_timeout=shutdown_timeout, + keepalive_timeout=keepalive_timeout, ssl_context=ssl_context, print=print, backlog=backlog, diff --git a/docs/web_reference.rst b/docs/web_reference.rst index 297a3a10d4e..4769a89749e 100644 --- a/docs/web_reference.rst +++ b/docs/web_reference.rst @@ -2737,7 +2737,8 @@ Utilities .. function:: run_app(app, *, debug=False, host=None, port=None, \ path=None, sock=None, shutdown_timeout=60.0, \ - ssl_context=None, print=print, backlog=128, \ + keepalive_timeout=75.0, ssl_context=None, \ + print=print, backlog=128, \ access_log_class=aiohttp.helpers.AccessLogger, \ access_log_format=aiohttp.helpers.AccessLogger.LOG_FORMAT, \ access_log=aiohttp.log.access_logger, \ @@ -2793,6 +2794,12 @@ Utilities timeout but closes a server in a few milliseconds. + :param float keepalive_timeout: a delay before a TCP connection is + closed after a HTTP request. The delay + allows for reuse of a TCP connection. + + .. versionadded:: 3.8 + :param ssl_context: :class:`ssl.SSLContext` for HTTPS server, ``None`` for HTTP connection. diff --git a/tests/test_run_app.py b/tests/test_run_app.py index 877cd8f425c..3c60807f2cc 100644 --- a/tests/test_run_app.py +++ b/tests/test_run_app.py @@ -16,6 +16,7 @@ from aiohttp import web from aiohttp.helpers import PY_37 from aiohttp.test_utils import make_mocked_coro +from aiohttp.web_runner import BaseRunner # Test for features of OS' socket support _has_unix_domain_socks = hasattr(socket, "AF_UNIX") @@ -824,6 +825,19 @@ async def on_startup(app): exc_handler.assert_called_with(patched_loop, msg) +def test_run_app_keepalive_timeout(patched_loop, mocker, monkeypatch): + new_timeout = 1234 + base_runner_init_orig = BaseRunner.__init__ + + def base_runner_init_spy(self, *args, **kwargs): + assert kwargs["keepalive_timeout"] == new_timeout + base_runner_init_orig(self, *args, **kwargs) + + app = web.Application() + monkeypatch.setattr(BaseRunner, "__init__", base_runner_init_spy) + web.run_app(app, keepalive_timeout=new_timeout, print=stopper(patched_loop)) + + @pytest.mark.skipif(not PY_37, reason="contextvars support is required") def test_run_app_context_vars(patched_loop): from contextvars import ContextVar