commit
8d2a05e788
|
@ -261,13 +261,26 @@ async def test_some_cancels_all(num_actors_and_errs, start_method):
|
|||
pytest.fail("Should have gotten a remote assertion error?")
|
||||
|
||||
|
||||
async def spawn_and_error(num) -> None:
|
||||
async def spawn_and_error(breadth, depth) -> None:
|
||||
name = tractor.current_actor().name
|
||||
async with tractor.open_nursery() as nursery:
|
||||
for i in range(num):
|
||||
await nursery.run_in_actor(
|
||||
f'{name}_errorer_{i}', assert_err
|
||||
)
|
||||
for i in range(breadth):
|
||||
if depth > 0:
|
||||
args = (
|
||||
f'spawner_{i}_depth_{depth}',
|
||||
spawn_and_error,
|
||||
)
|
||||
kwargs = {
|
||||
'breadth': breadth,
|
||||
'depth': depth - 1,
|
||||
}
|
||||
else:
|
||||
args = (
|
||||
f'{name}_errorer_{i}',
|
||||
assert_err,
|
||||
)
|
||||
kwargs = {}
|
||||
await nursery.run_in_actor(*args, **kwargs)
|
||||
|
||||
|
||||
@tractor_test
|
||||
|
@ -276,25 +289,34 @@ async def test_nested_multierrors(loglevel, start_method):
|
|||
This test goes only 2 nurseries deep but we should eventually have tests
|
||||
for arbitrary n-depth actor trees.
|
||||
"""
|
||||
if platform.system() == 'Windows':
|
||||
# Windows CI seems to be partifcularly fragile on Python 3.8..
|
||||
num_subactors = 2
|
||||
else:
|
||||
# XXX: any more then this and the forkserver will
|
||||
# start bailing hard...gotta look into it
|
||||
num_subactors = 4
|
||||
# XXX: forkserver can't seem to handle any more then 2 depth
|
||||
# process trees for whatever reason.
|
||||
# Any more process levels then this and we start getting pretty slow anyway
|
||||
depth = 3
|
||||
subactor_breadth = 2
|
||||
|
||||
try:
|
||||
async with tractor.open_nursery() as nursery:
|
||||
with trio.fail_after(120):
|
||||
try:
|
||||
async with tractor.open_nursery() as nursery:
|
||||
for i in range(subactor_breadth):
|
||||
await nursery.run_in_actor(
|
||||
f'spawner_{i}',
|
||||
spawn_and_error,
|
||||
breadth=subactor_breadth,
|
||||
depth=depth,
|
||||
)
|
||||
except trio.MultiError as err:
|
||||
assert len(err.exceptions) == subactor_breadth
|
||||
for subexc in err.exceptions:
|
||||
assert isinstance(subexc, tractor.RemoteActorError)
|
||||
if depth > 1 and subactor_breadth > 1:
|
||||
|
||||
for i in range(num_subactors):
|
||||
await nursery.run_in_actor(
|
||||
f'spawner_{i}',
|
||||
spawn_and_error,
|
||||
num=num_subactors,
|
||||
)
|
||||
except trio.MultiError as err:
|
||||
assert len(err.exceptions) == num_subactors
|
||||
for subexc in err.exceptions:
|
||||
assert isinstance(subexc, tractor.RemoteActorError)
|
||||
assert subexc.type is trio.MultiError
|
||||
# XXX not sure what's up with this..
|
||||
if platform.system() == 'Windows':
|
||||
assert (subexc.type is trio.MultiError) or (
|
||||
subexc.type is tractor.RemoteActorError)
|
||||
else:
|
||||
assert subexc.type is trio.MultiError
|
||||
else:
|
||||
assert (subexc.type is tractor.RemoteActorError) or (
|
||||
subexc.type is trio.Cancelled)
|
||||
|
|
|
@ -144,7 +144,7 @@ async def _invoke(
|
|||
|
||||
if not actor._rpc_tasks:
|
||||
log.info(f"All RPC tasks have completed")
|
||||
actor._no_more_rpc_tasks.set()
|
||||
actor._ongoing_rpc_tasks.set()
|
||||
|
||||
|
||||
class Actor:
|
||||
|
@ -183,9 +183,8 @@ class Actor:
|
|||
self._peer_connected: dict = {}
|
||||
self._no_more_peers = trio.Event()
|
||||
self._no_more_peers.set()
|
||||
|
||||
self._no_more_rpc_tasks = trio.Event()
|
||||
self._no_more_rpc_tasks.set()
|
||||
self._ongoing_rpc_tasks = trio.Event()
|
||||
self._ongoing_rpc_tasks.set()
|
||||
# (chan, cid) -> (cancel_scope, func)
|
||||
self._rpc_tasks: Dict[
|
||||
Tuple[Channel, str],
|
||||
|
@ -234,7 +233,7 @@ class Actor:
|
|||
) -> None:
|
||||
"""Entry point for new inbound connections to the channel server.
|
||||
"""
|
||||
self._no_more_peers.clear()
|
||||
self._no_more_peers = trio.Event()
|
||||
chan = Channel(stream=stream)
|
||||
log.info(f"New connection to us {chan}")
|
||||
|
||||
|
@ -448,7 +447,7 @@ class Actor:
|
|||
f"{cs}")
|
||||
else:
|
||||
# mark that we have ongoing rpc tasks
|
||||
self._no_more_rpc_tasks.clear()
|
||||
self._ongoing_rpc_tasks = trio.Event()
|
||||
log.info(f"RPC func is {func}")
|
||||
# store cancel scope such that the rpc task can be
|
||||
# cancelled gracefully if requested
|
||||
|
@ -709,10 +708,9 @@ class Actor:
|
|||
for (chan, cid) in tasks.copy():
|
||||
# TODO: this should really done in a nursery batch
|
||||
await self._cancel_task(cid, chan)
|
||||
# if tasks:
|
||||
log.info(
|
||||
f"Waiting for remaining rpc tasks to complete {tasks}")
|
||||
await self._no_more_rpc_tasks.wait()
|
||||
await self._ongoing_rpc_tasks.wait()
|
||||
|
||||
def cancel_server(self) -> None:
|
||||
"""Cancel the internal channel server nursery thereby
|
||||
|
|
Loading…
Reference in New Issue