[Python-Dev] Asynchronous context manager in a typical network server

Andrew Svetlov andrew.svetlov at gmail.com
Fri Dec 18 11:29:35 EST 2015


I my asyncio code typical initialization/finalization procedures are
much more complicated.
I doubt if common code can be extracted into asyncio.
Personally I don't feel the need for `wait_forever()` or
`loop.creae_context_task()`.

But even if you need it you may create it from scratch easy, isn't it?

On Fri, Dec 18, 2015 at 3:58 PM, Szieberth Ádám <sziebadam at gmail.com> wrote:
> Hi Developers!
>
> This is my first post. Please excuse me my poor English. If anyone is
> interested, I wrote a small introduction on my homepage. Link is at the bottom.
>
> This post is about how to effectively implement the new asynchronous context
> manager in a typical network server.
>
> I would appreciate and welcome any confirmation or critics whether my thinking
> is right or wrong. Thanks in advance!
>
> So, a typical server main code I used to see around is like this:
>
>     srv = loop.run_until_complete(create_server(handler, host, port))
>     try:
>         loop.run_forever()
>     except KeyboardInterrupt:
>         pass
>     finally:
>         # other tear down code may be here
>         srv.close()
>         loop.run_until_complete(srv.wait_closed())
>     loop.close()
>
> Note that `create_server()` here is not necessary
> `BaseEventLoop.create_server()`.
>
> The above code is not prepared to handle `OSError`s or any other `Exception`s
> (including a `KeyboardInterrupt` by a rapid Ctr+C) when setting up the server,
> it just prints the traceback to the console which is not user friendly.
> Moreover, I would expect from a server to handle the SIGTERM signal as well
> and tell its clients that it stops serving when not force killed.
>
> How the main code should create server, maintain the serving, deal with errors
> and close properly both the connections and the event loop when exiting
> without letting pending tasks around is not trivial. There are many questions
> on SO and other places of the internet regarding of this problem.
>
> My idea was to provide a simple code which is robust in terms of these
> concerns by profiting from the new asynchronous context manager pattern.
>
> The code of the magic methods of a typical awaitable `CreateServer` object
> seems rather trivial:
>
>     async def __aenter__(self):
>         self.server = await self
>         return self.server
>
>     async def __aexit__(self, exc_type, exc_value, traceback):
>         # other tear down code may be here
>         self.server.close()
>         await self.server.wait_closed()
>
> However, to make it work, a task has to be created:
>
>     async def server_task():
>         async with CreateServer(handler, host, port) as srv:
>             await asyncio.Future()  # wait forever
>
> I write some remarks regarding the above code to the end of this post. Note
> that `srv` is unreachable from outside which could be a problem in some cases.
> What is unavoidable: this task has to get cancelled explicitely by the main
> code which should look like this:
>
>     srvtsk = loop.create_task(server_task())
>
>     signal.signal(signal.SIGTERM, lambda si, fr: loop.call_soon(srvtsk.cancel))
>
>     while True:
>         try:
>             loop.run_until_complete(srvtsk)
>         except KeyboardInterrupt:
>             srvtsk.cancel()
>         except asyncio.CancelledError:
>             break
>         except Exception as err:
>             print(err)
>             break
>     loop.close()
>
> Note that when `CancelledError` gets raised, the tear down process is already
> done.
>
> Remarks:
>
> * It would be nice to have an `asyncio.wait_forever()` coroutine for dummy
>   context bodies.
> * Moreover, I also imagined an `BaseEventLoop.create_context_task(awithable,
>   body_coro_func=None)` method. The `body_coro_func` should default to
>   `asyncio.wait_forever()`, otherwise it should get whatever is returned by
>   `__aenter__` as a single argument. The returned Task object should also
>   provide a reference to that object.
>
> Best regards,
> Ádám
>
> (http://szieberthadam.github.io/)
> _______________________________________________
> Python-Dev mailing list
> Python-Dev at python.org
> https://mail.python.org/mailman/listinfo/python-dev
> Unsubscribe: https://mail.python.org/mailman/options/python-dev/andrew.svetlov%40gmail.com



-- 
Thanks,
Andrew Svetlov


More information about the Python-Dev mailing list