You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
When used with tricycle.BackgroundObject, parent scope cancellations leak through prematurely to trio-asyncio-managed asyncio tasks. I personally see this as a trio-asyncio bug, because in principal its adapter should transparently handle any differences so that tricycle.BackgroundObject isn't affected, but since you're the maintainer of both (at least it seems so), your opinion on that matters more than mine. :)
This repro script illustrates the problem in detail:
importasyncioimporttrioimporttrio_asynciofromtricycleimportBackgroundObjectclassAvailabilityBob(BackgroundObject):
trio_resource_available=Falseaio_resource_available=Falseasyncdef__open__(self) ->None:
print(
'What this "AvailabilityBob" object is doing is setting up two tasks in its service nursery that\n'"represent hypothetical maintainers of some resource that should remain available until the object's\n""context has been exited (this is what service nurseries are supposed to do for us). The only\n""difference between these two maintainer functions is that one is Trio-native and the other is\n""trio-asyncio-wrapped asyncio. The availability of the hypothetical resources is simulated by\n""maintaining two boolean attributes on the object. If both trio-asyncio and tricycle.BackgroundObject\n""are working correctly, their behavior should be the same.\n"
)
awaitself.nursery.start(self.trio_maintain_availability)
awaitself.nursery.start(self.aio_maintain_availability)
asyncdeftrio_maintain_availability(self, *, task_status: trio.TaskStatus[None] =trio.TASK_STATUS_IGNORED) ->None:
try:
self.trio_resource_available=Truetask_status.started()
awaittrio.sleep(float("inf"))
except* trio.Cancelled:
print("Trio maintainer cancelled!\n")
raisefinally:
self.trio_resource_available=False@trio_asyncio.aio_as_trioasyncdefaio_maintain_availability(self, *, task_status: trio.TaskStatus[None] =trio.TASK_STATUS_IGNORED) ->None:
try:
self.aio_resource_available=Truetask_status.started()
awaitasyncio.sleep(float("inf"))
exceptasyncio.CancelledError:
print("AsyncIO maintainer cancelled!\n")
raisefinally:
self.aio_resource_available=Falseasyncdefmain() ->None:
withtrio.CancelScope() ascancel_scope:
asyncwithtrio_asyncio.open_loop(), AvailabilityBob() asbob:
print(f"Entered bob's context: {bob.trio_resource_available=}{bob.aio_resource_available=}\n")
try:
awaittrio.sleep(0)
cancel_scope.cancel()
print("Cancelled bob's cancel scope.\n")
awaittrio.sleep(0)
finally:
withtrio.CancelScope() aserr_cancel_scope:
err_cancel_scope.shield=Trueprint(
"Entering the `finally` within bob's context, the asyncio maintainer has already been\n""cancelled, and usually already actually exited by this point:\n"f"{bob.trio_resource_available=}{bob.aio_resource_available=}\n"
)
awaittrio.sleep(0)
print(
"...but if it survived to that point, then certainly after a checkpoint, the asyncio\n""maintainer is gone, while the trio-native one continues to live (as both should):\n"f"{bob.trio_resource_available=}{bob.aio_resource_available=}\n"
)
trio.run(main, restrict_keyboard_interrupt_to_checkpoints=True, strict_exception_groups=True)
Incidentally, you may recall that we recently saw a similar behavior with asyncio async generators in the same context. I thought I'd mention it because it could point toward a common path where a holistic fix might be possible.
The text was updated successfully, but these errors were encountered:
mikenerone
changed the title
When used with tricycle.BackgroundObject, parent scope cancellations leak through to trio-asyncio-managed asyncio tasks.
When used with tricycle.BackgroundObject, parent scope cancellations leak through prematurely to trio-asyncio-managed asyncio tasks.
Jan 14, 2024
This is because a function wrapped in aio_as_trio runs in a different task from Trio's perspective (the task that's managing the asyncio loop), but tricycle was assuming that TaskStatus.started() would always run from within the new task. I uploaded oremanj/tricycle#27 which removes that assumption and fixes this example.
python
3.12.1 +trio
0.24.0 +trio-asyncio
0.13.0 +tricycle
0.4.0When used with
tricycle.BackgroundObject
, parent scope cancellations leak through prematurely totrio-asyncio
-managed asyncio tasks. I personally see this as atrio-asyncio
bug, because in principal its adapter should transparently handle any differences so thattricycle.BackgroundObject
isn't affected, but since you're the maintainer of both (at least it seems so), your opinion on that matters more than mine. :)This repro script illustrates the problem in detail:
Incidentally, you may recall that we recently saw a similar behavior with asyncio async generators in the same context. I thought I'd mention it because it could point toward a common path where a holistic fix might be possible.
The text was updated successfully, but these errors were encountered: