Port service+tests to latest `tractor` APIs
Continue the `repair_tests`-branch mission (already merged in this stack's ancestry, seedatad_servicef4c4f1e2which ported `conftest.py`) by fixing the remaining drift breakage vs. `tractor` git `main`; without these NOTHING boots since the `tractor.Address` port in604e5fcf. Deats, - normalize reg addrs via `wrap_address()` in `open_pikerd()` before `.unwrap()`-ing; entries may be raw `tuple`s when passed in from (test) client code. - port `check_for_service()` to `query_actor(regaddr=)` (was `arbiter_sockaddr=`) incl. its 2-tuple yield and the now-required `open_registry(addrs=)` arg. - `wait_for_actor(registry_addr=)` + `.chan.raddr.unwrap()` raw-tuple compares in `test_runtime_boot` and `ensure_service()`. - update `run_test_w_cancel_method()` for modern `tractor` cancel semantics: self-requested sub-service cancels are absorbed (no `ContextCancelled` raised to the opener) and single-exc groups collapse to a bare KBI. - `RemoteActorError.boxed_type` (was `.type`) and `Position.cumsize` (was `.size`) renames in tests. - bump the paper-EMS startup budget 9 -> 19s; it includes a live (kraken) symbology fetch so needs net headroom. - woops, add the missing comma in `.deribit.api`'s `tractor.trionics` import tuple.. (this patch was generated in some part by [`claude-code`][claude-code-gh]) [claude-code-gh]: https://github.com/anthropics/claude-code Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
parent
06c0a4856e
commit
47a7cf5502
|
|
@ -37,7 +37,7 @@ from rapidfuzz import process as fuzzy
|
||||||
import numpy as np
|
import numpy as np
|
||||||
from tractor.trionics import (
|
from tractor.trionics import (
|
||||||
broadcast_receiver,
|
broadcast_receiver,
|
||||||
maybe_open_context
|
maybe_open_context,
|
||||||
collapse_eg,
|
collapse_eg,
|
||||||
)
|
)
|
||||||
from tractor import to_asyncio
|
from tractor import to_asyncio
|
||||||
|
|
|
||||||
|
|
@ -214,7 +214,13 @@ async def open_pikerd(
|
||||||
trio.open_nursery() as service_tn,
|
trio.open_nursery() as service_tn,
|
||||||
):
|
):
|
||||||
for addr in reg_addrs:
|
for addr in reg_addrs:
|
||||||
uaddr: tuple = addr.unwrap()
|
# normalize to a wrapped `tractor` addr-type;
|
||||||
|
# entries may be raw `tuple`s when passed in
|
||||||
|
# from (test) client code.
|
||||||
|
wladdr = tractor.discovery._addr.wrap_address(
|
||||||
|
addr,
|
||||||
|
)
|
||||||
|
uaddr: tuple = wladdr.unwrap()
|
||||||
if (
|
if (
|
||||||
uaddr not in root_actor.accept_addrs
|
uaddr not in root_actor.accept_addrs
|
||||||
):
|
):
|
||||||
|
|
|
||||||
|
|
@ -225,10 +225,13 @@ async def check_for_service(
|
||||||
|
|
||||||
'''
|
'''
|
||||||
async with (
|
async with (
|
||||||
open_registry(ensure_exists=False) as reg_addr,
|
open_registry(
|
||||||
|
addrs=Registry.addrs,
|
||||||
|
ensure_exists=False,
|
||||||
|
) as reg_addrs,
|
||||||
tractor.query_actor(
|
tractor.query_actor(
|
||||||
service_name,
|
service_name,
|
||||||
arbiter_sockaddr=reg_addr,
|
regaddr=reg_addrs[0],
|
||||||
) as sockaddr,
|
) as (sockaddr, _),
|
||||||
):
|
):
|
||||||
return sockaddr
|
return sockaddr
|
||||||
|
|
|
||||||
|
|
@ -151,7 +151,7 @@ def load_and_check_pos(
|
||||||
# is the same the fqme.
|
# is the same the fqme.
|
||||||
pp: Position = table.pps[ppmsg.symbol]
|
pp: Position = table.pps[ppmsg.symbol]
|
||||||
|
|
||||||
assert ppmsg.size == pp.size
|
assert ppmsg.size == pp.cumsize
|
||||||
assert ppmsg.avg_price == pp.ppu
|
assert ppmsg.avg_price == pp.ppu
|
||||||
|
|
||||||
yield pp
|
yield pp
|
||||||
|
|
@ -179,7 +179,7 @@ def test_ems_err_on_bad_broker(
|
||||||
# NOTE: emsd should error on the actor's enabled modules
|
# NOTE: emsd should error on the actor's enabled modules
|
||||||
# import phase, when looking for a backend named `doggy`.
|
# import phase, when looking for a backend named `doggy`.
|
||||||
except tractor.RemoteActorError as re:
|
except tractor.RemoteActorError as re:
|
||||||
assert re.type is ModuleNotFoundError
|
assert re.boxed_type is ModuleNotFoundError
|
||||||
|
|
||||||
run_and_tollerate_cancels(load_bad_fqme)
|
run_and_tollerate_cancels(load_bad_fqme)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -53,11 +53,12 @@ def test_runtime_boot(
|
||||||
|
|
||||||
tractor.wait_for_actor(
|
tractor.wait_for_actor(
|
||||||
'pikerd',
|
'pikerd',
|
||||||
arbiter_sockaddr=daemon_addr,
|
registry_addr=daemon_addr,
|
||||||
) as portal,
|
) as portal,
|
||||||
):
|
):
|
||||||
assert pikerd_portal.channel.raddr == daemon_addr
|
uw_raddr: tuple = pikerd_portal.chan.raddr.unwrap()
|
||||||
assert pikerd_portal.channel.raddr == portal.channel.raddr
|
assert uw_raddr == daemon_addr
|
||||||
|
assert uw_raddr == portal.chan.raddr.unwrap()
|
||||||
|
|
||||||
# no service tasks should be started
|
# no service tasks should be started
|
||||||
assert not services.service_tasks
|
assert not services.service_tasks
|
||||||
|
|
@ -108,7 +109,7 @@ async def ensure_service(
|
||||||
sockaddr: tuple[str, int] | None = None,
|
sockaddr: tuple[str, int] | None = None,
|
||||||
) -> None:
|
) -> None:
|
||||||
async with find_service(name) as portal:
|
async with find_service(name) as portal:
|
||||||
remote_sockaddr = portal.channel.raddr
|
remote_sockaddr: tuple = portal.chan.raddr.unwrap()
|
||||||
print(f'FOUND `{name}` @ {remote_sockaddr}')
|
print(f'FOUND `{name}` @ {remote_sockaddr}')
|
||||||
|
|
||||||
if sockaddr:
|
if sockaddr:
|
||||||
|
|
@ -131,41 +132,50 @@ def run_test_w_cancel_method(
|
||||||
"was remotely cancelled by remote actor (\'pikerd\'")
|
"was remotely cancelled by remote actor (\'pikerd\'")
|
||||||
|
|
||||||
if cancel_method == 'sigint':
|
if cancel_method == 'sigint':
|
||||||
with pytest.raises(
|
# XXX: with modern `tractor` the (single-exc)
|
||||||
|
# group is collapsed so a bare KBI normally
|
||||||
|
# propagates; tolerate either form.
|
||||||
|
with pytest.raises((
|
||||||
|
KeyboardInterrupt,
|
||||||
BaseExceptionGroup,
|
BaseExceptionGroup,
|
||||||
) as exc_info:
|
)) as exc_info:
|
||||||
trio.run(main)
|
trio.run(main)
|
||||||
|
|
||||||
multi = exc_info.value
|
err = exc_info.value
|
||||||
|
match err:
|
||||||
for suberr in multi.exceptions:
|
case BaseExceptionGroup():
|
||||||
|
for suberr in err.exceptions:
|
||||||
match suberr:
|
match suberr:
|
||||||
# ensure we receive a remote cancellation error caused
|
# ensure we receive a remote
|
||||||
# by the pikerd root actor since we used the
|
# cancellation error caused by the
|
||||||
# `.cancel_service()` API above B)
|
# pikerd root actor.
|
||||||
case tractor.ContextCancelled():
|
case tractor.ContextCancelled():
|
||||||
assert cancelled_msg in suberr.args[0]
|
assert (
|
||||||
|
cancelled_msg
|
||||||
|
in
|
||||||
|
suberr.args[0]
|
||||||
|
)
|
||||||
|
|
||||||
case KeyboardInterrupt():
|
case KeyboardInterrupt():
|
||||||
pass
|
pass
|
||||||
|
|
||||||
case _:
|
case _:
|
||||||
pytest.fail(f'Unexpected error {suberr}')
|
pytest.fail(
|
||||||
|
f'Unexpected error {suberr}'
|
||||||
|
)
|
||||||
|
|
||||||
|
case KeyboardInterrupt():
|
||||||
|
pass
|
||||||
|
|
||||||
elif cancel_method == 'services':
|
elif cancel_method == 'services':
|
||||||
|
# XXX: cancelling our own sub-service via
|
||||||
# XXX NOTE: oddly, when you pass --pdb to pytest, i think since
|
# `Services.cancel_service()` is a *self*
|
||||||
# we also use that to enable the underlying tractor debug mode,
|
# requested cancel: modern `tractor` absorbs the
|
||||||
# it causes this to not raise for some reason? So if you see
|
# resulting `ContextCancelled` (canceller is our
|
||||||
# that while changing this test.. it's prolly that.
|
# own actor) so the runtime tears down gracefully
|
||||||
|
# with NO error raised to the opener.
|
||||||
with pytest.raises(
|
|
||||||
tractor.ContextCancelled
|
|
||||||
) as exc_info:
|
|
||||||
trio.run(main)
|
trio.run(main)
|
||||||
|
|
||||||
assert cancelled_msg in exc_info.value.args[0]
|
|
||||||
|
|
||||||
else:
|
else:
|
||||||
pytest.fail(f'Test is broken due to {cancel_method}')
|
pytest.fail(f'Test is broken due to {cancel_method}')
|
||||||
|
|
||||||
|
|
@ -197,7 +207,9 @@ def test_ensure_ems_in_paper_actors(
|
||||||
# ensure we timeout after is startup is too slow.
|
# ensure we timeout after is startup is too slow.
|
||||||
# TODO: something like this should be our start point for
|
# TODO: something like this should be our start point for
|
||||||
# benchmarking end-to-end startup B)
|
# benchmarking end-to-end startup B)
|
||||||
with trio.fail_after(9):
|
# NOTE: includes a live (kraken) symbology fetch so
|
||||||
|
# the budget needs some headroom for net latency..
|
||||||
|
with trio.fail_after(19):
|
||||||
async with (
|
async with (
|
||||||
open_test_pikerd() as (_, _, _, services),
|
open_test_pikerd() as (_, _, _, services),
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue