Relay `ContextCancelled` for `Portal.run()` cancelled remote tasks

zombie_lord_infinite
Tyler Goodlet 2021-10-12 12:03:15 -04:00
parent 39feb627a8
commit 2c74db9cb7
1 changed files with 22 additions and 6 deletions

View File

@ -58,7 +58,7 @@ async def _invoke(
Invoke local func and deliver result(s) over provided channel. Invoke local func and deliver result(s) over provided channel.
''' '''
__tracebackhide__ = True # __tracebackhide__ = True
treat_as_gen = False treat_as_gen = False
# possible a traceback (not sure what typing is for this..) # possible a traceback (not sure what typing is for this..)
@ -69,6 +69,7 @@ async def _invoke(
ctx = Context(chan, cid) ctx = Context(chan, cid)
context: bool = False context: bool = False
fname = func.__name__
if getattr(func, '_tractor_stream_function', False): if getattr(func, '_tractor_stream_function', False):
# handle decorated ``@tractor.stream`` async functions # handle decorated ``@tractor.stream`` async functions
@ -164,6 +165,7 @@ async def _invoke(
await chan.send({'return': await coro, 'cid': cid}) await chan.send({'return': await coro, 'cid': cid})
except trio.Cancelled as err: except trio.Cancelled as err:
tb = err.__traceback__ tb = err.__traceback__
raise
if cs.cancelled_caught: if cs.cancelled_caught:
@ -171,7 +173,6 @@ async def _invoke(
# so they can be unwrapped and displayed on the caller # so they can be unwrapped and displayed on the caller
# side! # side!
fname = func.__name__
if ctx._cancel_called: if ctx._cancel_called:
msg = f'{fname} cancelled itself' msg = f'{fname} cancelled itself'
@ -192,11 +193,25 @@ async def _invoke(
await chan.send({'functype': 'asyncfunc', 'cid': cid}) await chan.send({'functype': 'asyncfunc', 'cid': cid})
with cancel_scope as cs: with cancel_scope as cs:
task_status.started(cs) task_status.started(cs)
try:
await chan.send({'return': await coro, 'cid': cid}) await chan.send({'return': await coro, 'cid': cid})
except trio.Cancelled as err:
tb = err.__traceback__
raise
# await chan.send({'return': await coro, 'cid': cid})
if cs.cancelled_caught: if cs.cancelled_caught:
# if cs.cancel_called:
if cs.cancel_called:
msg = (
f'{fname} was remotely cancelled by its caller '
f'{ctx.chan.uid}'
)
else:
msg = f'{fname} cancelled itself'
raise ContextCancelled( raise ContextCancelled(
'cancelled', msg,
suberror_type=trio.Cancelled, suberror_type=trio.Cancelled,
) )
@ -561,7 +576,8 @@ class Actor:
send_chan, recv_chan = self._cids2qs[(chan.uid, cid)] send_chan, recv_chan = self._cids2qs[(chan.uid, cid)]
assert send_chan.cid == cid # type: ignore assert send_chan.cid == cid # type: ignore
# if 'error' in msg: if 'error' in msg:
recv_chan
# ctx = getattr(recv_chan, '_ctx', None) # ctx = getattr(recv_chan, '_ctx', None)
# if ctx: # if ctx:
# ctx._error_from_remote_msg(msg) # ctx._error_from_remote_msg(msg)
@ -1027,7 +1043,7 @@ class Actor:
raise raise
finally: finally:
log.info("Runtime nursery complete") log.runtime("root runtime nursery complete")
# tear down all lifetime contexts if not in guest mode # tear down all lifetime contexts if not in guest mode
# XXX: should this just be in the entrypoint? # XXX: should this just be in the entrypoint?