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
This commit is contained in:
Denis Makogon 2019-01-15 13:38:47 +02:00
parent 2af229eb1a
commit 391639210e
3 changed files with 26 additions and 3 deletions

View File

@ -1121,6 +1121,8 @@ class Sanic:
backlog: int = 100, backlog: int = 100,
stop_event: Any = None, stop_event: Any = None,
access_log: Optional[bool] = None, access_log: Optional[bool] = None,
return_asyncio_server=False,
asyncio_server_kwargs=None,
) -> None: ) -> None:
""" """
Asynchronous version of :func:`run`. Asynchronous version of :func:`run`.
@ -1154,6 +1156,13 @@ class Sanic:
:type stop_event: None :type stop_event: None
:param access_log: Enables writing access logs (slows server) :param access_log: Enables writing access logs (slows server)
:type access_log: bool :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 :return: Nothing
""" """
@ -1184,7 +1193,7 @@ class Sanic:
loop=get_event_loop(), loop=get_event_loop(),
protocol=protocol, protocol=protocol,
backlog=backlog, backlog=backlog,
run_async=True, run_async=return_asyncio_server,
) )
# Trigger before_start events # Trigger before_start events
@ -1193,7 +1202,10 @@ class Sanic:
server_settings.get("loop"), 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): async def trigger_events(self, events, loop):
"""Trigger events (functions or async) """Trigger events (functions or async)

View File

@ -656,6 +656,7 @@ def serve(
websocket_write_limit=2 ** 16, websocket_write_limit=2 ** 16,
state=None, state=None,
graceful_shutdown_timeout=15.0, graceful_shutdown_timeout=15.0,
asyncio_server_kwargs=None,
): ):
"""Start asynchronous HTTP Server on an individual process. """Start asynchronous HTTP Server on an individual process.
@ -700,6 +701,8 @@ def serve(
:param router: Router object :param router: Router object
:param graceful_shutdown_timeout: How long take to Force close non-idle :param graceful_shutdown_timeout: How long take to Force close non-idle
connection connection
:param asyncio_server_kwargs: key-value args for asyncio/uvloop
create_server method
:return: Nothing :return: Nothing
""" """
if not run_async: if not run_async:
@ -734,7 +737,9 @@ def serve(
state=state, state=state,
debug=debug, debug=debug,
) )
asyncio_server_kwargs = (
asyncio_server_kwargs if asyncio_server_kwargs else {}
)
server_coroutine = loop.create_server( server_coroutine = loop.create_server(
server, server,
host, host,
@ -743,6 +748,7 @@ def serve(
reuse_port=reuse_port, reuse_port=reuse_port,
sock=sock, sock=sock,
backlog=backlog, backlog=backlog,
**asyncio_server_kwargs
) )
# Instead of pulling time at the end of every request, # Instead of pulling time at the end of every request,

View File

@ -17,6 +17,11 @@ def test_app_loop_running(app):
assert response.text == "pass" 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): def test_app_loop_not_running(app):
with pytest.raises(SanicException) as excinfo: with pytest.raises(SanicException) as excinfo:
app.loop app.loop