Error leaving open_loop() with background Trio sandwich running
oremanj opened this issue · comments
The platform: CPython 3.6.7 on Linux, Trio 0.11.0, trio-asyncio 0.10.0.
The setup: Inside a trio-asyncio async loop, I have an asyncio task running in the background, that's in turn awaiting a long-running Trio task (using trio_as_aio appropriately). I exit the async with trio_asyncio.open_loop():
block with the background task still running. In code:
import trio
import trio_asyncio
import asyncio
@trio_asyncio.trio_as_aio
async def trio_grandchild():
await trio.sleep_forever()
async def asyncio_child():
await asyncio.sleep(1)
await trio_grandchild()
@trio_asyncio.aio_as_trio
async def asyncio_spawner():
asyncio.ensure_future(asyncio_child())
async def trio_main():
async with trio_asyncio.open_loop() as loop:
await asyncio_spawner()
await trio.sleep(2)
if __name__ == "__main__":
trio.run(trio_main)
The error, after 2 seconds:
Exception in default exception handler
Traceback (most recent call last):
File "/usr/scratch/labtestvenv/lib/python3.6/site-packages/trio_asyncio/base.py", line 300, in __run_trio
res = await proc(*args)
File "t.py", line 7, in trio_grandchild
await trio.sleep_forever()
File "/usr/scratch/labtestvenv/lib/python3.6/site-packages/trio/_timeouts.py", line 51, in sleep_forever
await _core.wait_task_rescheduled(lambda _: _core.Abort.SUCCEEDED)
File "/usr/scratch/labtestvenv/lib/python3.6/site-packages/trio/_core/_traps.py", line 166, in wait_task_rescheduled
return (await _async_yield(WaitTaskRescheduled(abort_func))).unwrap()
File "/usr/scratch/labtestvenv/lib/python3.6/site-packages/outcome/_sync.py", line 111, in unwrap
raise captured_error
File "/usr/scratch/labtestvenv/lib/python3.6/site-packages/trio/_core/_run.py", line 740, in raise_cancel
raise Cancelled._init()
trio.Cancelled
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/usr/lib/python3.6/asyncio/base_events.py", line 1299, in call_exception_handler
self.default_exception_handler(context)
File "/usr/scratch/labtestvenv/lib/python3.6/site-packages/trio_asyncio/async_.py", line 47, in default_exception_handler
raise RuntimeError(message)
RuntimeError: Task was destroyed but it is pending!
Exception in default exception handler
Traceback (most recent call last):
File "/usr/scratch/labtestvenv/lib/python3.6/site-packages/trio_asyncio/base.py", line 300, in __run_trio
res = await proc(*args)
File "t.py", line 7, in trio_grandchild
await trio.sleep_forever()
File "/usr/scratch/labtestvenv/lib/python3.6/site-packages/trio/_timeouts.py", line 51, in sleep_forever
await _core.wait_task_rescheduled(lambda _: _core.Abort.SUCCEEDED)
File "/usr/scratch/labtestvenv/lib/python3.6/site-packages/trio/_core/_traps.py", line 166, in wait_task_rescheduled
return (await _async_yield(WaitTaskRescheduled(abort_func))).unwrap()
File "/usr/scratch/labtestvenv/lib/python3.6/site-packages/outcome/_sync.py", line 111, in unwrap
raise captured_error
File "/usr/scratch/labtestvenv/lib/python3.6/site-packages/trio/_core/_run.py", line 740, in raise_cancel
raise Cancelled._init()
trio.Cancelled
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/usr/lib/python3.6/asyncio/base_events.py", line 1299, in call_exception_handler
self.default_exception_handler(context)
File "/usr/scratch/labtestvenv/lib/python3.6/site-packages/trio_asyncio/async_.py", line 49, in default_exception_handler
raise exception
File "/usr/scratch/labtestvenv/lib/python3.6/site-packages/trio_asyncio/handles.py", line 135, in _call_async
await self._callback(self)
File "/usr/scratch/labtestvenv/lib/python3.6/site-packages/trio_asyncio/base.py", line 306, in __run_trio
f.set_exception(exc)
File "/usr/scratch/labtestvenv/lib/python3.6/site-packages/trio_asyncio/base.py", line 399, in call_soon
return self._queue_handle(Handle(callback, args, self, context=context, is_sync=True))
File "/usr/scratch/labtestvenv/lib/python3.6/site-packages/trio_asyncio/async_.py", line 18, in _queue_handle
self._check_closed()
File "/usr/lib/python3.6/asyncio/base_events.py", line 366, in _check_closed
raise RuntimeError('Event loop is closed')
RuntimeError: Event loop is closed
(In a classic display of asyncio robustness, this is just stderr -- the script exits successfully.)
This seems to occur because a Cancelled exception escapes from BaseTrioEventLoop.__run_trio
after the open_loop()
block's __aexit__
cancels its enclosing nursery's cancel scope. The future that __run_trio
is working with isn't cancelled, so the cancellation check in __run_trio
doesn't fire.