2025-08-19 19:21:45 +00:00
|
|
|
import trio
|
|
|
|
|
import tractor
|
|
|
|
|
|
|
|
|
|
|
2026-07-02 16:32:49 +00:00
|
|
|
async def main() -> None:
|
2026-08-29 23:01:34 +00:00
|
|
|
'''
|
|
|
|
|
Enter shielded debugging after root cancellation, then fail.
|
|
|
|
|
|
|
|
|
|
'''
|
2025-08-19 19:21:45 +00:00
|
|
|
async with tractor.open_root_actor(
|
|
|
|
|
debug_mode=True,
|
|
|
|
|
loglevel='cancel',
|
|
|
|
|
) as _root:
|
|
|
|
|
|
|
|
|
|
# manually trigger self-cancellation and wait
|
|
|
|
|
# for it to fully trigger.
|
|
|
|
|
_root.cancel_soon()
|
|
|
|
|
await _root._cancel_complete.wait()
|
|
|
|
|
print('root cancelled')
|
|
|
|
|
|
|
|
|
|
# now ensure we can still use the REPL
|
|
|
|
|
try:
|
|
|
|
|
await tractor.pause()
|
|
|
|
|
except trio.Cancelled as _taskc:
|
2026-08-29 23:01:34 +00:00
|
|
|
root_cs: trio.CancelScope
|
|
|
|
|
assert (
|
|
|
|
|
root_cs := _root._root_tn.cancel_scope
|
|
|
|
|
).cancel_called
|
2025-08-19 19:21:45 +00:00
|
|
|
# NOTE^^ above logic but inside `open_root_actor()` and
|
|
|
|
|
# passed to the `shield=` expression is effectively what
|
|
|
|
|
# we're testing here!
|
|
|
|
|
await tractor.pause(shield=root_cs.cancel_called)
|
|
|
|
|
|
2026-08-29 23:01:34 +00:00
|
|
|
# XXX, if shield logic *is wrong* inside
|
|
|
|
|
# `open_root_actor()`'s crash-handler block this should never
|
|
|
|
|
# be interacted, instead `trio.Cancelled` would be bubbled
|
|
|
|
|
# up: the original BUG.
|
2025-08-19 19:21:45 +00:00
|
|
|
assert 0
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
|
|
trio.run(main)
|