Re: [Python-Dev] Asynchronous context manager in a typical network server
On Fri, Dec 18, 2015 at 4:09 PM, Guido van Rossum wrote: > >> It's 11 days. Which is pretty reasonable server uptime. >> > > Oops, blame the repr() of datetime.timedelta. I'm sorry I so rashly > thought I could do better than the OP. > A helpful trivia: a year is approximately π times 10 million seconds. ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] Asynchronous context manager in a typical network server
On 18.12.2015 22:09, Guido van Rossum wrote: I guess we could make the default arg to sleep() 1e9. Or make it None and special-case it. I don't feel strongly about this -- I'm not sure how baffling it would be to accidentally leave out the delay and find your code sleeps forever rather than raising an error (since if you don't expect the infinite default you may not expect this kind of behavior). But I do feel it's not important enough to add a new function or method. Why still guessing the best surrogate for infinity? Seems like python is just missing int('inf'). :/ Best, Sven ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] Asynchronous context manager in a typical network server
Using an Event is slightly better because you just wait for it -- you don't have to catch an exception. It's just not one of the better-known parts of asyncio. On Fri, Dec 18, 2015 at 1:42 PM, Andrew Barnert wrote: > On Friday, December 18, 2015 1:09 PM, Guido van Rossum > wrote: > > > >I guess we could make the default arg to sleep() 1e9. Or make it None and > special-case it. I don't feel strongly about this -- I'm not sure how > baffling it would be to accidentally leave out the delay and find your code > sleeps forever rather than raising an error (since if you don't expect the > infinite default you may not expect this kind of behavior). > > Yeah, that is a potential problem. > > The traditional C solution is to just allow passing -1 to mean "forever",* > ideally with a constant so you can just say "sleep(FOREVER)". Which, in > Python terms, would presumably mean "asyncio.sleep(asyncio.forever)", and > it could be a unique object or an enum value or something instead of > actually being -1. > > * Or at least "until this rolls over 31/32/63/64 bits", which is where you > get those 49-day bugs from... but that wouldn't be an issue in Python > > > But I do feel it's not important enough to add a new function or method. > > Definitely agreed. > >However, I don't think "forever" and "until cancelled" are really the > same thing. "Forever" can only be interrupted by loop.stop(); "until > cancelled" requires indicating how to cancel it, and there the OP's > approach is about the best you can do. (Or you could use the Event class, > but that's really just a wrapper on top of a Future made to look more like > threading.Event in its API.) > > > OK, I thought the OP's code looked pretty clear as written: he wants to > wait until cancelled, so he waits on something that pretty clearly won't > ever finish until he's cancelled. If that (or an Event or whatever) is the > best way to spell this, then I can't really think of any good uses for > sleep(forever). > -- --Guido van Rossum (python.org/~guido) ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] Asynchronous context manager in a typical network server
On Friday, December 18, 2015 1:09 PM, Guido van Rossum wrote: >I guess we could make the default arg to sleep() 1e9. Or make it None and >special-case it. I don't feel strongly about this -- I'm not sure how baffling >it would be to accidentally leave out the delay and find your code sleeps >forever rather than raising an error (since if you don't expect the infinite >default you may not expect this kind of behavior). Yeah, that is a potential problem. The traditional C solution is to just allow passing -1 to mean "forever",* ideally with a constant so you can just say "sleep(FOREVER)". Which, in Python terms, would presumably mean "asyncio.sleep(asyncio.forever)", and it could be a unique object or an enum value or something instead of actually being -1. * Or at least "until this rolls over 31/32/63/64 bits", which is where you get those 49-day bugs from... but that wouldn't be an issue in Python > But I do feel it's not important enough to add a new function or method. Definitely agreed. >However, I don't think "forever" and "until cancelled" are really the same >thing. "Forever" can only be interrupted by loop.stop(); "until cancelled" >requires indicating how to cancel it, and there the OP's approach is about the >best you can do. (Or you could use the Event class, but that's really just a >wrapper on top of a Future made to look more like threading.Event in its API.) OK, I thought the OP's code looked pretty clear as written: he wants to wait until cancelled, so he waits on something that pretty clearly won't ever finish until he's cancelled. If that (or an Event or whatever) is the best way to spell this, then I can't really think of any good uses for sleep(forever). ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] Asynchronous context manager in a typical network server
> I guess we could make the default arg to sleep() 1e9. Or make it None and > special-case it. By writing the OP, I considered suggesting this approach and rejected. I would have suggest the using Ellipsis (`...`) for the special case which seemed to explain more what is done plus it can hardly given unintentionally. I ended up suggesting `wait_forever()` though. Ádám (http://szieberthadam.github.io/) ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] Asynchronous context manager in a typical network server
> Maybe you can help by submitting a patch that prevents this error! Are you > interested? I'd be honored. Ádám (http://szieberthadam.github.io/) P.S.: Was thinking about a longer answer but finally I ended up with this one :) ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] Asynchronous context manager in a typical network server
Thanks for your reply Andrew! > 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? Indeed. I was prepared for such opinions which is OK. It is better to think it through several times twice before introducing a new feature to an API. I myself feel that `loop.create_context_task()` may be too specific. The `asyncio.wait_forever()` coro seems much simple. Surely it must get investigated whether there are a significal amount of patterns where this coro could take part. I introduced one but surely that is not enough, only if it is so awesome that everyone starts using it which I doubt. :) Ádám (http://szieberthadam.github.io/) ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] Asynchronous context manager in a typical network server
On Fri, Dec 18, 2015 at 12:45 PM, Andrew Barnert wrote: > On Dec 18, 2015, at 10:36, Guido van Rossum wrote: > > On Fri, Dec 18, 2015 at 10:25 AM, Szieberth Ádám > wrote: > >> Thanks for your reply Guido! >> >> > - In theory, instead of waiting for a Future that is cancelled by a >> > handler, you should be able to use asyncio.sleep() with a very large >> number >> > (e.g. a million seconds). >> >> I was thinking on this too but it seemed less explicit to me than >> awaiting a >> pure Future with a short comment. Moreover, even millions of seconds can >> pass. >> > > 11 years. > > > It's 11 days. Which is pretty reasonable server uptime. > Oops, blame the repr() of datetime.timedelta. I'm sorry I so rashly thought I could do better than the OP. > And probably just outside the longest test you're ever going to run. I > don't trust myself to pick "a big number" when the numbers get this big. > But I still sometimes sneak one past myself somehow. Hence my suggestion > for a way to actually say "forever". > I guess we could make the default arg to sleep() 1e9. Or make it None and special-case it. I don't feel strongly about this -- I'm not sure how baffling it would be to accidentally leave out the delay and find your code sleeps forever rather than raising an error (since if you don't expect the infinite default you may not expect this kind of behavior). But I do feel it's not important enough to add a new function or method. However, I don't think "forever" and "until cancelled" are really the same thing. "Forever" can only be interrupted by loop.stop(); "until cancelled" requires indicating how to cancel it, and there the OP's approach is about the best you can do. (Or you could use the Event class, but that's really just a wrapper on top of a Future made to look more like threading.Event in its API.) -- --Guido van Rossum (python.org/~guido) ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] Asynchronous context manager in a typical network server
On Dec 18, 2015, at 10:36, Guido van Rossum wrote: > >> On Fri, Dec 18, 2015 at 10:25 AM, Szieberth Ádám wrote: >> Thanks for your reply Guido! >> >> > - In theory, instead of waiting for a Future that is cancelled by a >> > handler, you should be able to use asyncio.sleep() with a very large number >> > (e.g. a million seconds). >> >> I was thinking on this too but it seemed less explicit to me than awaiting a >> pure Future with a short comment. Moreover, even millions of seconds can >> pass. > > 11 years. It's 11 days. Which is pretty reasonable server uptime. And probably just outside the longest test you're ever going to run. I don't trust myself to pick "a big number" when the numbers get this big. But I still sometimes sneak one past myself somehow. Hence my suggestion for a way to actually say "forever". ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] Asynchronous context manager in a typical network server
On Dec 18, 2015, at 10:25, Szieberth Ádám wrote: > >> - In theory, instead of waiting for a Future that is cancelled by a >> handler, you should be able to use asyncio.sleep() with a very large number >> (e.g. a million seconds). > > I was thinking on this too but it seemed less explicit to me than awaiting a > pure Future with a short comment. Moreover, even millions of seconds can pass. Yes, and these are really fun to debug. When a customer comes to you with "it was running fine for a few months and then suddenly it started going crazy, but I can't reproduce it", unless you happen to remember that you decided 10 million seconds was "forever" and ask whether "a few months" specifically means a few days short of 4 months... (At least with 24 and 49 days I know to look for which library used a C integer for milliseconds.) Really, I don't see anything wrong with the way the OP wrote it. Is that just because I have bad C habits (/* Useless select because there's no actual sleep function that allows SIGUSR to wake us without allowing all signals to wake us that works on both Solaris and IRIX */) and it really does look misleading to people who aren't warped like that? If so, would it be worth having an actual way to say "sleep forever (until canceled)"? Even if, under the covers, this only sleeps for 5 years or so, a Y52K problem that can be solved by just pushing a new patch release for Python instead of for every separate server written in Python is probably a bit nicer. :) ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] Asynchronous context manager in a typical network server
No, it just means Windows users should not try to catch signals on Windows. Signals don't really exist there, and the simulation supporting only a few signals is awful (last I tried ^C was only processed when the process was waiting for input from stdin, and I had to use the BREAK key to stop runaway processes, which killed my shell window as well as the Python process). If you want orderly shutdown of a server process on Windows, you should probably listen for connections on a dedicated port on localhost and use that as an indication to stop the server. On Fri, Dec 18, 2015 at 11:29 AM, Glenn Linderman wrote: > On 12/18/2015 10:36 AM, Guido van Rossum wrote: > > I was opted to the signal module because `signal` documentation suggest >> that >> it alos supports Windows while asyncio documentation states that `loop. >> add_signal_handler()` is UNIX only. >> > > Unfortunately that's true, but using the signal module with asyncio the > way you did is *not* safe. The only safe way is to use the > loop.add_signal_handler() interface. > > > Does this mean Windows users should not bother trying to use asyncio ? > > (I haven't yet, due to lack of time, but I'd hate to think of folks, > including myself in the future, investing a lot of time developing > something and then discover it can never be reliable, due to this sort of > "unsafe" or "not-available-on-Windows" feature.) > > ___ > Python-Dev mailing list > Python-Dev@python.org > https://mail.python.org/mailman/listinfo/python-dev > Unsubscribe: > https://mail.python.org/mailman/options/python-dev/guido%40python.org > > -- --Guido van Rossum (python.org/~guido) ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] Asynchronous context manager in a typical network server
On 12/18/2015 10:36 AM, Guido van Rossum wrote: I was opted to the signal module because `signal` documentation suggest that it alos supports Windows while asyncio documentation states that `loop. add_signal_handler()` is UNIX only. Unfortunately that's true, but using the signal module with asyncio the way you did is *not* safe. The only safe way is to use the loop.add_signal_handler() interface. Does this mean Windows users should not bother trying to use asyncio ? (I haven't yet, due to lack of time, but I'd hate to think of folks, including myself in the future, investing a lot of time developing something and then discover it can never be reliable, due to this sort of "unsafe" or "not-available-on-Windows" feature.) ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] Asynchronous context manager in a typical network server
On Fri, Dec 18, 2015 at 10:25 AM, Szieberth Ádám wrote: > Thanks for your reply Guido! > > > - Instead of calling signal.signal() yourself, you should use > > loop.add_signal_handler(). It makes sure your signal handler doesn't run > > while another handler is already running. > > I was opted to the signal module because `signal` documentation suggest > that > it alos supports Windows while asyncio documentation states that `loop. > add_signal_handler()` is UNIX only. > Unfortunately that's true, but using the signal module with asyncio the way you did is *not* safe. The only safe way is to use the loop.add_signal_handler() interface. > > - I'm unclear on why you want a wait_forever() instead of using > > loop.run_forever(). Can you clarify? > > As I see `loop.run_forever()` is an issue from _outside_ while an `await > wait_forever()` would be an _inside_ declaration making explicit what the > task > does (serving forever). > > My OP suggest that it seemed to me quite helpful inside async context. > However, I wanted to share my approach to get a confirmation that I am not > on > a totally wrong way with this. > Well, if you look at the toy servers in the asyncio examples directory, they all use run_forever(). I agree that from within the loop that's not possible, but I don't think it's such a common thing (you typically write a framework for creating servers once and that's the only place where you would need this). IOW I think your solution of waiting for a Future is the right way. > > - In theory, instead of waiting for a Future that is cancelled by a > > handler, you should be able to use asyncio.sleep() with a very large > number > > (e.g. a million seconds). > > I was thinking on this too but it seemed less explicit to me than awaiting > a > pure Future with a short comment. Moreover, even millions of seconds can > pass. > 11 years. That's quite some trust you put in your hardware... But you can use a billion. I think by 11000 years from now you can retire your server. :-) > > Your handler could then just call loop.stop(). > > For some reason I don't like bothering with the event loop from inside > awaitables. It seems hacky to me since it breaks the hierarhy of who > controlls > who. > Fair enough -- you've actually internalized the asyncio philosophy quite well. > > However, I just tested this and it raises "RuntimeError: Event loop > stopped > > before Future completed." so ignore this until we've fixed it. :-) > > This is the exception I saw so many times by trying to close an asyncio > program! I guess I am not the only one. This may be one of the most > frustrating aspects of the library. Yet, it inspired me to figure out a > plain > pattern to avoid it, which may not the right one. However, I would like to > signal that it would be nice to help developers with useful patterns and > documentation to avoid RuntimeErrors and the frustration that goes with > them. > Maybe you can help by submitting a patch that prevents this error! Are you interested? > Ádám > (http://szieberthadam.github.io/) > > PS: I will replay to others as well, but first I had to play with my son. > :) > -- --Guido van Rossum (python.org/~guido) ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] Asynchronous context manager in a typical network server
Thanks for your reply Guido! > - Instead of calling signal.signal() yourself, you should use > loop.add_signal_handler(). It makes sure your signal handler doesn't run > while another handler is already running. I was opted to the signal module because `signal` documentation suggest that it alos supports Windows while asyncio documentation states that `loop. add_signal_handler()` is UNIX only. > - I'm unclear on why you want a wait_forever() instead of using > loop.run_forever(). Can you clarify? As I see `loop.run_forever()` is an issue from _outside_ while an `await wait_forever()` would be an _inside_ declaration making explicit what the task does (serving forever). My OP suggest that it seemed to me quite helpful inside async context. However, I wanted to share my approach to get a confirmation that I am not on a totally wrong way with this. > - In theory, instead of waiting for a Future that is cancelled by a > handler, you should be able to use asyncio.sleep() with a very large number > (e.g. a million seconds). I was thinking on this too but it seemed less explicit to me than awaiting a pure Future with a short comment. Moreover, even millions of seconds can pass. > Your handler could then just call loop.stop(). For some reason I don't like bothering with the event loop from inside awaitables. It seems hacky to me since it breaks the hierarhy of who controlls who. > However, I just tested this and it raises "RuntimeError: Event loop stopped > before Future completed." so ignore this until we've fixed it. :-) This is the exception I saw so many times by trying to close an asyncio program! I guess I am not the only one. This may be one of the most frustrating aspects of the library. Yet, it inspired me to figure out a plain pattern to avoid it, which may not the right one. However, I would like to signal that it would be nice to help developers with useful patterns and documentation to avoid RuntimeErrors and the frustration that goes with them. Ádám (http://szieberthadam.github.io/) PS: I will replay to others as well, but first I had to play with my son. :) ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] Asynchronous context manager in a typical network server
On Fri, 18 Dec 2015 18:29:35 +0200, Andrew Svetlov wrote: > 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? In my own asyncio code I wrote a generic context manager to hold references to all the top level tasks my ap needs, which automatically handles the teardown when loop.stop() is called from my SIGTERM signal handler. However, (and here we get to the python-dev content of this post :), I think we are too early in the uptake of asyncio to be ready to say what additional high-level features are well defined enough and useful enough to become part of the standard library. In any case discussions like this really belong on the asyncio-specific mailing list, which I gather is the python-tulip Google Group (I suppose I really ought to sign up...) --David ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com
Re: [Python-Dev] Asynchronous context manager in a typical network server
I agree with Andrew that there are too many different scenarios and requirements to make this a useful library function. Some notes on the actual code you posted: - Instead of calling signal.signal() yourself, you should use loop.add_signal_handler(). It makes sure your signal handler doesn't run while another handler is already running. - If you add a handler for SIGINT you can control what happens when the user hits ^C (again, ensuring the handler already running isn't interrupted halfway through). - I'm unclear on why you want a wait_forever() instead of using loop.run_forever(). Can you clarify? - In theory, instead of waiting for a Future that is cancelled by a handler, you should be able to use asyncio.sleep() with a very large number (e.g. a million seconds). Your handler could then just call loop.stop(). However, I just tested this and it raises "RuntimeError: Event loop stopped before Future completed." so ignore this until we've fixed it. :-) On Fri, Dec 18, 2015 at 5:58 AM, Szieberth Ádám 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@python.org > https://mail.python.org/mailman/listinfo/python-dev > Unsubscribe: > https://mail.python.org/mailman/options/python-dev/guido%40python.org > -- --Guido van Rossum (python.org/~guido) _
Re: [Python-Dev] Asynchronous context manager in a typical network server
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 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@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 ___ Python-Dev mailing list Python-Dev@python.org https://mail.python.org/mailman/listinfo/python-dev Unsubscribe: https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com