2021-12-13 18:08:32 +00:00
|
|
|
# tractor: structured concurrent "actors".
|
|
|
|
|
# Copyright 2018-eternity Tyler Goodlet.
|
|
|
|
|
|
|
|
|
|
# This program is free software: you can redistribute it and/or modify
|
|
|
|
|
# it under the terms of the GNU Affero General Public License as published by
|
|
|
|
|
# the Free Software Foundation, either version 3 of the License, or
|
|
|
|
|
# (at your option) any later version.
|
|
|
|
|
|
|
|
|
|
# This program is distributed in the hope that it will be useful,
|
|
|
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
# GNU Affero General Public License for more details.
|
|
|
|
|
|
|
|
|
|
# You should have received a copy of the GNU Affero General Public License
|
|
|
|
|
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
|
|
|
|
2021-10-04 16:02:21 +00:00
|
|
|
'''
|
|
|
|
|
Actor cluster helpers.
|
|
|
|
|
|
|
|
|
|
'''
|
2021-10-16 15:33:39 +00:00
|
|
|
from __future__ import annotations
|
2025-02-25 16:20:57 +00:00
|
|
|
from contextlib import (
|
|
|
|
|
asynccontextmanager as acm,
|
|
|
|
|
)
|
2021-10-04 16:02:21 +00:00
|
|
|
from multiprocessing import cpu_count
|
2025-02-25 16:20:57 +00:00
|
|
|
from typing import (
|
|
|
|
|
AsyncGenerator,
|
|
|
|
|
)
|
2021-10-04 16:02:21 +00:00
|
|
|
|
|
|
|
|
import trio
|
|
|
|
|
import tractor
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@acm
|
|
|
|
|
async def open_actor_cluster(
|
|
|
|
|
modules: list[str],
|
|
|
|
|
count: int = cpu_count(),
|
2022-12-12 00:47:59 +00:00
|
|
|
names: list[str] | None = None,
|
2021-10-17 12:40:09 +00:00
|
|
|
hard_kill: bool = False,
|
2022-12-12 00:47:59 +00:00
|
|
|
|
|
|
|
|
# passed through verbatim to ``open_root_actor()``
|
|
|
|
|
**runtime_kwargs,
|
|
|
|
|
|
2021-10-04 20:01:09 +00:00
|
|
|
) -> AsyncGenerator[
|
2021-10-23 22:47:26 +00:00
|
|
|
dict[str, tractor.Portal],
|
|
|
|
|
None,
|
2021-10-04 20:01:09 +00:00
|
|
|
]:
|
2021-10-04 16:02:21 +00:00
|
|
|
|
|
|
|
|
portals: dict[str, tractor.Portal] = {}
|
|
|
|
|
|
|
|
|
|
if not names:
|
2021-10-22 00:59:15 +00:00
|
|
|
names = [f'worker_{i}' for i in range(count)]
|
2021-10-04 16:02:21 +00:00
|
|
|
|
|
|
|
|
if not len(names) == count:
|
|
|
|
|
raise ValueError(
|
|
|
|
|
'Number of names is {len(names)} but count it {count}')
|
|
|
|
|
|
2025-07-08 16:51:08 +00:00
|
|
|
async with (
|
|
|
|
|
# tractor.trionics.collapse_eg(),
|
|
|
|
|
tractor.open_nursery(
|
|
|
|
|
**runtime_kwargs,
|
|
|
|
|
) as an
|
|
|
|
|
):
|
|
|
|
|
async with (
|
2025-07-24 22:17:50 +00:00
|
|
|
# tractor.trionics.collapse_eg(),
|
2025-07-08 16:51:08 +00:00
|
|
|
trio.open_nursery() as tn,
|
|
|
|
|
tractor.trionics.maybe_raise_from_masking_exc()
|
|
|
|
|
):
|
Use `.aid.uid` to avoid deprecation warns
I started getting annoyed by all the warnings from `pytest` during work
on macos suport in CI, so this replaces all `Actor.uid`/`Channel.uid`
accesses with `.aid.uid` (or `.aid.reprol()` for log msgs) across the
core runtime and IPC subsystems to avoid the noise.
This also provides incentive to start the adjustment to all
`.uid`-holding/tracking internal `dict`-tables/data-structures to
instead use `.msg.types.Aid`. Hopefully that will come a (vibed?) follow
up shortly B)
Deats,
- `._context`: swap all `self._actor.uid`, `self.chan.uid`,
and `portal.actor.uid` refs to `.aid.uid`; use
`.aid.reprol()` for log/error formatting.
- `._rpc`: same treatment for `actor.uid`, `chan.uid` in
log msgs and cancel-scope handling; fix `str(err)` typo
in `ContextCancelled` log.
- `._runtime`: update `chan.uid` -> `chan.aid.uid` in ctx
cache lookups, RPC `Start` msg, registration and
cancel-request handling; improve ctxc log formatting.
- `._spawn`: replace all `subactor.uid` with
`.aid.uid` for child-proc tracking, IPC peer waiting,
debug-lock acquisition, and nursery child dict ops.
- `._supervise`: same for `subactor.uid` in cancel and
portal-wait paths; use `actor.aid.uid` for error dict.
- `._state`: fix `last.uid` -> `last.aid.uid` in
`current_actor()` error msg.
Also,
- `._chan`: make `Channel.aid` a proper `@property` backed
by `._aid` so we can add validation/typing later.
- `.log`: use `current_actor().aid.uuid` instead of
`.uid[1]` for actor-uid log field.
- `.msg.types`: add TODO comment for `Start.aid` field
conversion.
(this commit msg was generated in some part by [`claude-code`][claude-code-gh])
[claude-code-gh]: https://github.com/anthropics/claude-code
2026-03-08 19:27:48 +00:00
|
|
|
uid = tractor.current_actor().aid.uid
|
2021-10-04 16:02:21 +00:00
|
|
|
|
2021-10-22 00:59:15 +00:00
|
|
|
async def _start(name: str) -> None:
|
2021-11-02 19:40:15 +00:00
|
|
|
name = f'{uid[0]}.{name}'
|
2021-10-22 00:59:15 +00:00
|
|
|
portals[name] = await an.start_actor(
|
|
|
|
|
enable_modules=modules,
|
|
|
|
|
name=name,
|
|
|
|
|
)
|
2021-10-04 16:02:21 +00:00
|
|
|
|
2021-10-22 00:59:15 +00:00
|
|
|
for name in names:
|
2025-07-08 16:51:08 +00:00
|
|
|
tn.start_soon(_start, name)
|
2021-10-04 16:02:21 +00:00
|
|
|
|
|
|
|
|
assert len(portals) == count
|
|
|
|
|
yield portals
|
2021-10-17 12:40:09 +00:00
|
|
|
await an.cancel(hard_kill=hard_kill)
|