Tons of interpeer test cleanup
Drop all the nested `@acm` blocks and defunct comments from initial validations. Add some todos for cases that are still unclear such as whether the caller / streamer should have `.cancelled_caught == True` in it's teardown.multihomed
parent
ef0cfc4b20
commit
d651f3d8e9
|
@ -194,59 +194,33 @@ async def stream_from_peer(
|
||||||
try:
|
try:
|
||||||
async with (
|
async with (
|
||||||
tractor.wait_for_actor(peer_name) as peer,
|
tractor.wait_for_actor(peer_name) as peer,
|
||||||
# peer.open_context(stream_ints) as (peer_ctx, first),
|
peer.open_context(stream_ints) as (peer_ctx, first),
|
||||||
# peer_ctx.open_stream() as stream,
|
peer_ctx.open_stream() as stream,
|
||||||
):
|
):
|
||||||
async with (
|
await ctx.started()
|
||||||
peer.open_context(stream_ints) as (peer_ctx, first),
|
# XXX QUESTIONS & TODO: for further details around this
|
||||||
# peer_ctx.open_stream() as stream,
|
# in the longer run..
|
||||||
):
|
# https://github.com/goodboy/tractor/issues/368
|
||||||
# # try:
|
# - should we raise `ContextCancelled` or `Cancelled` (rn
|
||||||
async with (
|
# it does latter) and should/could it be implemented
|
||||||
peer_ctx.open_stream() as stream,
|
# as a general injection override for `trio` such
|
||||||
):
|
# that ANY next checkpoint would raise the "cancel
|
||||||
|
# error type" of choice?
|
||||||
await ctx.started()
|
# - should the `ContextCancelled` bubble from
|
||||||
# XXX QUESTIONS & TODO: for further details around this
|
# all `Context` and `MsgStream` apis wherein it
|
||||||
# in the longer run..
|
# prolly makes the most sense to make it
|
||||||
# https://github.com/goodboy/tractor/issues/368
|
# a `trio.Cancelled` subtype?
|
||||||
# - should we raise `ContextCancelled` or `Cancelled` (rn
|
# - what about IPC-transport specific errors, should
|
||||||
# it does latter) and should/could it be implemented
|
# they bubble from the async for and trigger
|
||||||
# as a general injection override for `trio` such
|
# other special cases?
|
||||||
# that ANY next checkpoint would raise the "cancel
|
# NOTE: current ctl flow:
|
||||||
# error type" of choice?
|
# - stream raises `trio.EndOfChannel` and
|
||||||
# - should the `ContextCancelled` bubble from
|
# exits the loop
|
||||||
# all `Context` and `MsgStream` apis wherein it
|
# - `.open_context()` will raise the ctxcanc
|
||||||
# prolly makes the most sense to make it
|
# received from the sleeper.
|
||||||
# a `trio.Cancelled` subtype?
|
async for msg in stream:
|
||||||
# - what about IPC-transport specific errors, should
|
assert msg is not None
|
||||||
# they bubble from the async for and trigger
|
print(msg)
|
||||||
# other special cases?
|
|
||||||
# try:
|
|
||||||
# NOTE: current ctl flow:
|
|
||||||
# - stream raises `trio.EndOfChannel` and
|
|
||||||
# exits the loop
|
|
||||||
# - `.open_context()` will raise the ctxcanc
|
|
||||||
# received from the sleeper.
|
|
||||||
async for msg in stream:
|
|
||||||
assert msg is not None
|
|
||||||
print(msg)
|
|
||||||
# finally:
|
|
||||||
# await trio.sleep(0.1)
|
|
||||||
# from tractor import pause
|
|
||||||
# await pause()
|
|
||||||
|
|
||||||
# except BaseException as berr:
|
|
||||||
# with trio.CancelScope(shield=True):
|
|
||||||
# await tractor.pause()
|
|
||||||
# raise
|
|
||||||
|
|
||||||
# except trio.Cancelled:
|
|
||||||
# with trio.CancelScope(shield=True):
|
|
||||||
# await tractor.pause()
|
|
||||||
# raise # XXX NEVER MASK IT
|
|
||||||
# from tractor import pause
|
|
||||||
# await pause()
|
|
||||||
|
|
||||||
# NOTE: cancellation of the (sleeper) peer should always
|
# NOTE: cancellation of the (sleeper) peer should always
|
||||||
# cause a `ContextCancelled` raise in this streaming
|
# cause a `ContextCancelled` raise in this streaming
|
||||||
|
@ -265,11 +239,10 @@ async def stream_from_peer(
|
||||||
|
|
||||||
# we never requested cancellation
|
# we never requested cancellation
|
||||||
assert not peer_ctx.cancel_called
|
assert not peer_ctx.cancel_called
|
||||||
# the `.open_context()` exit definitely
|
# the `.open_context()` exit definitely caught
|
||||||
# caught a cancellation in the internal `Context._scope`
|
# a cancellation in the internal `Context._scope` since
|
||||||
# since likely the runtime called `_deliver_msg()`
|
# likely the runtime called `_deliver_msg()` after
|
||||||
# after receiving the remote error from the streaming
|
# receiving the remote error from the streaming task.
|
||||||
# task.
|
|
||||||
assert peer_ctx.cancelled_caught
|
assert peer_ctx.cancelled_caught
|
||||||
|
|
||||||
# TODO / NOTE `.canceller` won't have been set yet
|
# TODO / NOTE `.canceller` won't have been set yet
|
||||||
|
@ -284,8 +257,9 @@ async def stream_from_peer(
|
||||||
assert not ctx.canceller
|
assert not ctx.canceller
|
||||||
assert 'canceller' in peer_ctx.canceller
|
assert 'canceller' in peer_ctx.canceller
|
||||||
|
|
||||||
|
raise
|
||||||
# TODO: IN THEORY we could have other cases depending on
|
# TODO: IN THEORY we could have other cases depending on
|
||||||
# who cancels first, the root actor or the canceller peer.
|
# who cancels first, the root actor or the canceller peer?.
|
||||||
#
|
#
|
||||||
# 1- when the peer request is first then the `.canceller`
|
# 1- when the peer request is first then the `.canceller`
|
||||||
# field should obvi be set to the 'canceller' uid,
|
# field should obvi be set to the 'canceller' uid,
|
||||||
|
@ -294,12 +268,12 @@ async def stream_from_peer(
|
||||||
# `trio.Cancelled` implicitly raised
|
# `trio.Cancelled` implicitly raised
|
||||||
# assert ctx.canceller[0] == 'root'
|
# assert ctx.canceller[0] == 'root'
|
||||||
# assert peer_ctx.canceller[0] == 'sleeper'
|
# assert peer_ctx.canceller[0] == 'sleeper'
|
||||||
raise
|
|
||||||
|
|
||||||
raise RuntimeError(
|
raise RuntimeError(
|
||||||
'peer never triggered local `ContextCancelled`?'
|
'peer never triggered local `ContextCancelled`?'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
'error_during_ctxerr_handling',
|
'error_during_ctxerr_handling',
|
||||||
[False, True],
|
[False, True],
|
||||||
|
@ -361,6 +335,7 @@ def test_peer_canceller(
|
||||||
'''
|
'''
|
||||||
async def main():
|
async def main():
|
||||||
async with tractor.open_nursery(
|
async with tractor.open_nursery(
|
||||||
|
# NOTE: to halt the peer tasks on ctxc, uncomment this.
|
||||||
# debug_mode=True
|
# debug_mode=True
|
||||||
) as an:
|
) as an:
|
||||||
canceller: Portal = await an.start_actor(
|
canceller: Portal = await an.start_actor(
|
||||||
|
@ -402,7 +377,6 @@ def test_peer_canceller(
|
||||||
|
|
||||||
try:
|
try:
|
||||||
print('PRE CONTEXT RESULT')
|
print('PRE CONTEXT RESULT')
|
||||||
# await tractor.pause()
|
|
||||||
await sleeper_ctx.result()
|
await sleeper_ctx.result()
|
||||||
|
|
||||||
# should never get here
|
# should never get here
|
||||||
|
@ -410,9 +384,8 @@ def test_peer_canceller(
|
||||||
'Context.result() did not raise ctx-cancelled?'
|
'Context.result() did not raise ctx-cancelled?'
|
||||||
)
|
)
|
||||||
|
|
||||||
# TODO: not sure why this isn't catching
|
# should always raise since this root task does
|
||||||
# but maybe we need an `ExceptionGroup` and
|
# not request the sleeper cancellation ;)
|
||||||
# the whole except *errs: thinger in 3.11?
|
|
||||||
except ContextCancelled as ctxerr:
|
except ContextCancelled as ctxerr:
|
||||||
print(f'CAUGHT REMOTE CONTEXT CANCEL {ctxerr}')
|
print(f'CAUGHT REMOTE CONTEXT CANCEL {ctxerr}')
|
||||||
|
|
||||||
|
@ -430,9 +403,6 @@ def test_peer_canceller(
|
||||||
# block it should be.
|
# block it should be.
|
||||||
assert not sleeper_ctx.cancelled_caught
|
assert not sleeper_ctx.cancelled_caught
|
||||||
|
|
||||||
# TODO: a test which ensures this error is
|
|
||||||
# bubbled and caught (NOT MASKED) by the
|
|
||||||
# runtime!!!
|
|
||||||
if error_during_ctxerr_handling:
|
if error_during_ctxerr_handling:
|
||||||
raise RuntimeError('Simulated error during teardown')
|
raise RuntimeError('Simulated error during teardown')
|
||||||
|
|
||||||
|
@ -458,6 +428,7 @@ def test_peer_canceller(
|
||||||
# - `.canceller` (uid of cancel-causing actor-task)
|
# - `.canceller` (uid of cancel-causing actor-task)
|
||||||
# - `._remote_error` (any `RemoteActorError`
|
# - `._remote_error` (any `RemoteActorError`
|
||||||
# instance from other side of context)
|
# instance from other side of context)
|
||||||
|
# TODO: are we really planning to use this tho?
|
||||||
# - `._cancel_msg` (any msg that caused the
|
# - `._cancel_msg` (any msg that caused the
|
||||||
# cancel)
|
# cancel)
|
||||||
|
|
||||||
|
@ -482,21 +453,33 @@ def test_peer_canceller(
|
||||||
ctx is sleeper_ctx
|
ctx is sleeper_ctx
|
||||||
or ctx is caller_ctx
|
or ctx is caller_ctx
|
||||||
):
|
):
|
||||||
assert re.canceller == canceller.channel.uid
|
assert (
|
||||||
|
re.canceller
|
||||||
|
==
|
||||||
|
ctx.canceller
|
||||||
|
==
|
||||||
|
canceller.channel.uid
|
||||||
|
)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
assert re.canceller == root.uid
|
assert (
|
||||||
|
re.canceller
|
||||||
# each context should have received
|
==
|
||||||
# a silently absorbed context cancellation
|
ctx.canceller
|
||||||
# from its peer actor's task.
|
==
|
||||||
# assert ctx.chan.uid == ctx.canceller
|
root.uid
|
||||||
|
)
|
||||||
|
|
||||||
# CASE: standard teardown inside in `.open_context()` block
|
# CASE: standard teardown inside in `.open_context()` block
|
||||||
else:
|
else:
|
||||||
assert ctxerr.canceller == sleeper_ctx.canceller
|
assert ctxerr.canceller == sleeper_ctx.canceller
|
||||||
# assert ctxerr.canceller[0] == 'canceller'
|
assert (
|
||||||
# assert sleeper_ctx.canceller[0] == 'canceller'
|
ctxerr.canceller[0]
|
||||||
|
==
|
||||||
|
sleeper_ctx.canceller[0]
|
||||||
|
==
|
||||||
|
'canceller'
|
||||||
|
)
|
||||||
|
|
||||||
# the sleeper's remote error is the error bubbled
|
# the sleeper's remote error is the error bubbled
|
||||||
# out of the context-stack above!
|
# out of the context-stack above!
|
||||||
|
@ -509,21 +492,29 @@ def test_peer_canceller(
|
||||||
|
|
||||||
# root doesn't cancel sleeper since it's
|
# root doesn't cancel sleeper since it's
|
||||||
# cancelled by its peer.
|
# cancelled by its peer.
|
||||||
# match ctx:
|
|
||||||
# case sleeper_ctx:
|
|
||||||
if ctx is sleeper_ctx:
|
if ctx is sleeper_ctx:
|
||||||
assert not ctx.cancel_called
|
assert not ctx.cancel_called
|
||||||
# wait WHY?
|
# since sleeper_ctx.result() IS called
|
||||||
|
# above we should have (silently)
|
||||||
|
# absorbed the corresponding
|
||||||
|
# `ContextCancelled` for it and thus
|
||||||
|
# the logic inside `.cancelled_caught`
|
||||||
|
# should trigger!
|
||||||
assert ctx.cancelled_caught
|
assert ctx.cancelled_caught
|
||||||
|
|
||||||
elif ctx is caller_ctx:
|
elif ctx is caller_ctx:
|
||||||
# since its context was remotely
|
# since its context was remotely
|
||||||
# cancelled, we never needed to
|
# cancelled, we never needed to
|
||||||
# call `Context.cancel()` bc our
|
# call `Context.cancel()` bc it was
|
||||||
# context was already remotely
|
# done by the peer and also we never
|
||||||
# cancelled by the time we'd do it.
|
|
||||||
assert ctx.cancel_called
|
assert ctx.cancel_called
|
||||||
|
|
||||||
|
# TODO: figure out the details of
|
||||||
|
# this..
|
||||||
|
# if you look the `._local_error` here
|
||||||
|
# is a multi of ctxc + 2 Cancelleds?
|
||||||
|
# assert not ctx.cancelled_caught
|
||||||
|
|
||||||
else:
|
else:
|
||||||
assert ctx.cancel_called
|
assert ctx.cancel_called
|
||||||
assert not ctx.cancelled_caught
|
assert not ctx.cancelled_caught
|
||||||
|
@ -551,7 +542,6 @@ def test_peer_canceller(
|
||||||
# itself errors.
|
# itself errors.
|
||||||
assert sleeper_ctx.cancelled_caught
|
assert sleeper_ctx.cancelled_caught
|
||||||
|
|
||||||
# await tractor.pause()
|
|
||||||
raise # always to ensure teardown
|
raise # always to ensure teardown
|
||||||
|
|
||||||
if error_during_ctxerr_handling:
|
if error_during_ctxerr_handling:
|
||||||
|
|
Loading…
Reference in New Issue