Apologies if this is just my fault. Feel free to Won't Fix it if so 😄 I'm toying around with trio-asyncio and had a hard time figuring out what went wrong here.
If you have a toy program like such
import trio
import trio_asyncio
async def setAfterWait(event):
await trio.sleep(5)
print('setting')
event.set()
async def asyncio_loop(event):
async with trio_asyncio.open_loop() as loop:
print('in')
await event.wait()
loop.stop()
print('stopped')
print('dedented')
async def main():
event = trio.Event()
async with trio.open_nursery() as nursery:
nursery.start_soon(setAfterWait, event)
nursery.start_soon(serve, event)
And you run this, you get print out like:
in
<5 second pause>
setting
stopped
And then the program hangs forever (you can KI it, which is always nice!). However, if you remove the explicit call to loop.stop(), it works as you expect.
in
<5 seconds>
setting
stopped
dedented
I ran into this while trying to debug a more complicated program where a loop.stop() had been added in a misguided attempt to debug a different shutdown issue (forgetting to cancel a nursery that had a bunch of "background" tasks).
@oremanj helped me get a task tree dump, and it looks like trio-asyncio gets stuck here:
[ 4] | |-- task __main__.asyncio_loop:
[ 5] | | asyncio_loop at __mp_main__:14
[ 6] | | _AsyncGeneratorContextManager.__aexit__ at async_generator._util:42
[ 7] | | step at async_generator._impl:366
[ 8] | | nursery nursery in open_loop at trio_asyncio.async_:108
[ ] | | +-- nested child:
[ 9] | | open_loop at trio_asyncio.async_:123
[ 10] | | Event.wait at trio._sync:73
[ 11] | | ParkingLot.park at trio._core._parking_lot:137
[ 12] | | wait_task_rescheduled at trio._core._traps:166
I'm guessing that what happens is that the __aexit__ is submitting a callback (TrioEventLoop._queue_handle) after the loop has been stopped, so it never actually fires. I definitely messed this up, but I figured I'd write this up in case anyone else runs into it. If there's a reasonable way to fix/document better, I'd be happy to pitch in.
You're right – calling loop.stop yourself is a bad idea in conjunction with trio-asyncio.
I'd appreciate a PR with some text that warns against doing that kind of thing.
Apologies if this is just my fault. Feel free to Won't Fix it if so 😄 I'm toying around with trio-asyncio and had a hard time figuring out what went wrong here.
If you have a toy program like such
And you run this, you get print out like:
And then the program hangs forever (you can KI it, which is always nice!). However, if you remove the explicit call to
loop.stop()
, it works as you expect.I ran into this while trying to debug a more complicated program where a
loop.stop()
had been added in a misguided attempt to debug a different shutdown issue (forgetting to cancel a nursery that had a bunch of "background" tasks).@oremanj helped me get a task tree dump, and it looks like
trio-asyncio
gets stuck here:I'm guessing that what happens is that the
__aexit__
is submitting a callback (TrioEventLoop._queue_handle
) after the loop has been stopped, so it never actually fires. I definitely messed this up, but I figured I'd write this up in case anyone else runs into it. If there's a reasonable way to fix/document better, I'd be happy to pitch in.Thanks!