From 391639210e046a38365e26667cfe654e47767c21 Mon Sep 17 00:00:00 2001 From: Denis Makogon Date: Tue, 15 Jan 2019 13:38:47 +0200 Subject: [PATCH] make Sanic.create_server return an asyncio.Server - adding 2 new parameters to Sanic.create_server: * return_asyncio_server=False - defines whether there's a need to return an asyncio.Server or run it right away * asyncio_server_kwargs=None - for python 3.7 uvloop doesn't support all necessary features like "start_serving", so, in order to make sanic work well with asyncio from 3.7 there's a need to introduce generic way for passing kwargs for "loop.create_server" Closes: #1469 --- sanic/app.py | 16 ++++++++++++++-- sanic/server.py | 8 +++++++- tests/test_app.py | 5 +++++ 3 files changed, 26 insertions(+), 3 deletions(-) diff --git a/sanic/app.py b/sanic/app.py index c1a39413..bb2561e6 100644 --- a/sanic/app.py +++ b/sanic/app.py @@ -1121,6 +1121,8 @@ class Sanic: backlog: int = 100, stop_event: Any = None, access_log: Optional[bool] = None, + return_asyncio_server=False, + asyncio_server_kwargs=None, ) -> None: """ Asynchronous version of :func:`run`. @@ -1154,6 +1156,13 @@ class Sanic: :type stop_event: None :param access_log: Enables writing access logs (slows server) :type access_log: bool + :param return_asyncio_server: flag that defines whether there's a need + to return asyncio.Server or + start it serving right away + :type return_asyncio_server: bool + :param asyncio_server_kwargs: key-value arguments for + asyncio/uvloop create_server method + :type asyncio_server_kwargs: dict :return: Nothing """ @@ -1184,7 +1193,7 @@ class Sanic: loop=get_event_loop(), protocol=protocol, backlog=backlog, - run_async=True, + run_async=return_asyncio_server, ) # Trigger before_start events @@ -1193,7 +1202,10 @@ class Sanic: server_settings.get("loop"), ) - return await serve(**server_settings) + return await serve( + asyncio_server_kwargs=asyncio_server_kwargs, + **server_settings + ) async def trigger_events(self, events, loop): """Trigger events (functions or async) diff --git a/sanic/server.py b/sanic/server.py index e3879a80..605e35e3 100644 --- a/sanic/server.py +++ b/sanic/server.py @@ -656,6 +656,7 @@ def serve( websocket_write_limit=2 ** 16, state=None, graceful_shutdown_timeout=15.0, + asyncio_server_kwargs=None, ): """Start asynchronous HTTP Server on an individual process. @@ -700,6 +701,8 @@ def serve( :param router: Router object :param graceful_shutdown_timeout: How long take to Force close non-idle connection + :param asyncio_server_kwargs: key-value args for asyncio/uvloop + create_server method :return: Nothing """ if not run_async: @@ -734,7 +737,9 @@ def serve( state=state, debug=debug, ) - + asyncio_server_kwargs = ( + asyncio_server_kwargs if asyncio_server_kwargs else {} + ) server_coroutine = loop.create_server( server, host, @@ -743,6 +748,7 @@ def serve( reuse_port=reuse_port, sock=sock, backlog=backlog, + **asyncio_server_kwargs ) # Instead of pulling time at the end of every request, diff --git a/tests/test_app.py b/tests/test_app.py index be2a45da..e27a4373 100644 --- a/tests/test_app.py +++ b/tests/test_app.py @@ -17,6 +17,11 @@ def test_app_loop_running(app): assert response.text == "pass" +def test_create_asyncio_server(app): + asyncio_srv = app.create_server(return_asyncio_server=True) + assert isinstance(asyncio_srv, asyncio.AbstractServer) + + def test_app_loop_not_running(app): with pytest.raises(SanicException) as excinfo: app.loop