<div dir="auto">Twisted's reactor API has some lifecycle hooks:<div dir="auto"><br></div><div dir="auto"><a href="https://twistedmatrix.com/documents/18.4.0/api/twisted.internet.interfaces.IReactorCore.html#addSystemEventTrigger">https://twistedmatrix.com/documents/18.4.0/api/twisted.internet.interfaces.IReactorCore.html#addSystemEventTrigger</a><br></div><div dir="auto"><br></div><div dir="auto">My impression is that this is actually pretty awkward for twisted/asyncio interoperability, because if you're trying to use a twisted library on top of an asyncio loop then there's no reliable way to implement these methods. And twisted uses these internally for things like managing its thread pool.</div><div dir="auto"><br></div><div dir="auto">There is some subtlety though because in twisted, reactors can't transition from the stopped state back into the running state, which implies an invariant where the start and shutdown hooks can be called at most once.</div><div dir="auto"><br></div><div dir="auto">Anyway, I'm not a twisted expert, but wanted to flag this so you all know that if you're talking about adding lifecycle hooks then you know to go talk to them and get the details.</div><div dir="auto"><br></div><div dir="auto">(Trio does have some sorta-kinda analogous functionality. Specifically it has a concept of "system tasks" that are automatically cancelled when the main task exits, so they have a chance to do any cleanup at that point. But trio's lifecycle model is so different that I'm not sure how helpful this is.)</div><div dir="auto"><br></div><div dir="auto">-n</div></div><br><div class="gmail_quote"><div dir="ltr">On Tue, Jun 5, 2018, 05:48 Michel Desmoulin <<a href="mailto:desmoulinmichel@gmail.com">desmoulinmichel@gmail.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">After years of playing with asyncio, I'm still having a harder time<br>
using it than any other async architecture around. There are a lot of<br>
different reasons for it, but this mail want to address one particular one:<br>
<br>
The event loop and policy can be tweaked at any time, by anyone.<br>
<br>
Now, it's hard enough to have to deal, manually, with a low-level event<br>
loop. But having it exposed that much, and it being that flexible means<br>
any code can just do whatever it wants with it, and make a mess.<br>
<br>
Several things in particular, comes to mind:<br>
<br>
- Changing the event loop policy<br>
- Changing the event loop<br>
- Spawning a new loop<br>
- Starting the loop<br>
- Stopping the loop<br>
- Closing the loop<br>
<br>
Now, if you want to make any serious project with it, you currently have<br>
to guard against all of those, especially if you want to have proper<br>
cleanup code, good error message and a decent debugging experience.<br>
<br>
I tried to do it for one year, and currently, it's very hard. You have a<br>
lot of checks to make, redundantly in a lot of places. Some things can<br>
only be done by providing a custom event policy/loop yourself, and, of<br>
course, expecting (aka documenting and praying) that it's used.<br>
<br>
For a lot of things, when it breaks, the people that haven't read the<br>
doc in depth will have a hard time to understand the problem after the fact.<br>
<br>
Sometimes, it's just that your code use somebody else code that is not<br>
here to read your doc anymore. Now you have to check their code to<br>
understand what they are doing that breaks your expectations about the<br>
loop / policy or workflow.<br>
<br>
Barring the creating of an entire higher level framework that everybody<br>
will agree on using and that makes messing up way harder, we can improve<br>
this situation by adding hooks to those events.<br>
<br>
I hence propose to add:<br>
<br>
- asyncio.on_change_policy(cb:Callable[[EventLoopPolicy,<br>
EventLoopPolicy], EventLoopPolicy])<br>
<br>
- asyncio.on_set_event_loop(cb:Callable[[EventLoop, EventLoop], EventLoop])<br>
<br>
- asyncio.on_create_event_loop(cb:Callable[[EventLoop], EventLoop])<br>
<br>
- EventLoop.on_start(cb:Callable[EventLoop])<br>
<br>
- EventLoop.on_stop(cb:Awaitable[EventLoop])<br>
<br>
- EventLoop.on_close(cb:Callable[EventLoop])<br>
<br>
- EventLoop.on_set_debug_mode(cb:Callable[[loop]])<br>
<br>
This would allow to implement safer, more robust and easier to debug<br>
code. E.G:<br>
<br>
- you can raise a warning stating that if somebody changes the event<br>
policy, it must inherit from your custom one or deal with disabled features<br>
<br>
- you can raise an exception on loop swap and forbid it, saying that<br>
your small script doesn't support it yet so that it's easy to understand<br>
the limit of your code<br>
<br>
- you can hook on the event loop life cycle to automatically get on<br>
board, or run clean up code, starting logging, warn that you were<br>
supposed to start the loop yourself, etc<br>
_______________________________________________<br>
Python-ideas mailing list<br>
<a href="mailto:Python-ideas@python.org" target="_blank" rel="noreferrer">Python-ideas@python.org</a><br>
<a href="https://mail.python.org/mailman/listinfo/python-ideas" rel="noreferrer noreferrer" target="_blank">https://mail.python.org/mailman/listinfo/python-ideas</a><br>
Code of Conduct: <a href="http://python.org/psf/codeofconduct/" rel="noreferrer noreferrer" target="_blank">http://python.org/psf/codeofconduct/</a><br>
</blockquote></div>