94 lines
2.5 KiB
Python
94 lines
2.5 KiB
Python
'''
|
|
Watch `tractor` actors (de)register themselves, live, via TIPC's
|
|
topology service.
|
|
|
|
`open_topology_events()` subscribes to the kernel's name table
|
|
and yields a `trio` receive-channel of `publish`/`withdraw`
|
|
events. That's **push-based** service discovery: no registrar
|
|
round-trip, no polling — the kernel tells you the instant any
|
|
actor anywhere in the cluster comes or goes.
|
|
|
|
Run,
|
|
|
|
sudo modprobe tipc
|
|
python watch_nametable.py
|
|
|
|
'''
|
|
from __future__ import annotations
|
|
|
|
import trio
|
|
import tractor
|
|
from tractor.ipc._tipc import (
|
|
TIPCNameEvent,
|
|
is_tipc_available,
|
|
open_topology_events,
|
|
)
|
|
|
|
|
|
@tractor.context
|
|
async def wait_until_cancelled(
|
|
ctx: tractor.Context,
|
|
) -> None:
|
|
await ctx.started()
|
|
await trio.sleep_forever()
|
|
|
|
|
|
async def print_events(
|
|
events: trio.MemoryReceiveChannel[TIPCNameEvent],
|
|
) -> None:
|
|
glyphs: dict[str, str] = {
|
|
'published': '[+]',
|
|
'withdrawn': '[-]',
|
|
'timeout': '[!]',
|
|
}
|
|
async for ev in events:
|
|
print(
|
|
f' {glyphs.get(ev.kind, "[?]")} {ev.kind:<10} '
|
|
f'instance={ev.addr._instance:<12} '
|
|
f'port=0x{ev.node:08x}:{ev.ref}'
|
|
)
|
|
|
|
|
|
async def main() -> None:
|
|
# NOTE, subscribe BEFORE booting the runtime so we catch the
|
|
# root actor's own publication too.
|
|
async with open_topology_events() as events:
|
|
async with trio.open_nursery() as tn:
|
|
tn.start_soon(print_events, events)
|
|
|
|
print('watching the TIPC name table..\n')
|
|
async with tractor.open_nursery(
|
|
enable_transports=['tipc'],
|
|
) as an:
|
|
await trio.sleep(0.3)
|
|
|
|
print('\nspawning subactors..')
|
|
portals: list[tractor.Portal] = []
|
|
for name in ('donny', 'walter', 'dude'):
|
|
portals.append(
|
|
await an.start_actor(
|
|
name,
|
|
enable_modules=[__name__],
|
|
)
|
|
)
|
|
await trio.sleep(0.2)
|
|
|
|
print('\ntearing down..')
|
|
for ptl in portals:
|
|
await ptl.cancel_actor()
|
|
await trio.sleep(0.2)
|
|
|
|
await an.cancel()
|
|
|
|
await trio.sleep(0.5)
|
|
tn.cancel_scope.cancel()
|
|
|
|
|
|
if __name__ == '__main__':
|
|
if not is_tipc_available():
|
|
raise RuntimeError(
|
|
'The `tipc` kernel module is not loaded!\n'
|
|
' |_try: `sudo modprobe tipc`\n'
|
|
)
|
|
trio.run(main)
|