Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Supervisors

A supervisor is an actor that starts other actors (children), watches them, and restarts them when they crash.

In fauxtp, the supervisor is implemented in src/fauxtp/supervisor.py and is intentionally minimal:

Child specifications

A ChildSpec defines how to start a child actor.

from fauxtp.supervisor import ChildSpec
from my_app.workers import Worker

spec = ChildSpec(
    actor=Worker,
    name="worker-1",
    args=(1, 2, 3),
)

Notes:

Restart strategies

Restart strategies are defined by RestartStrategy:

Starting a supervisor

The supervisor is itself an actor, so you start it the same way as any other actor: inside an AnyIO TaskGroup (structured concurrency).

import anyio

from fauxtp.registry import Registry
from fauxtp.supervisor import Supervisor, ChildSpec, RestartStrategy
from my_app.workers import Worker


async def main():
    async with anyio.create_task_group() as tg:
        registry = await Registry.start(task_group=tg)

        _sup_pid = await Supervisor.start(
            children=[
                ChildSpec(actor=Worker, name="worker-1", args=(1,)),
                ChildSpec(actor=Worker, name="worker-2", args=(2,)),
            ],
            strategy=RestartStrategy.ONE_FOR_ONE,
            registry=registry,
            task_group=tg,
        )


anyio.run(main)

If you pass registry=None, the supervisor will start its own internal Registry as a child actor (see Supervisor.init()).

Registry integration

When the supervisor starts a child, it registers that child’s name into the registry:

Callers can resolve a child PID with a call:

from fauxtp.messaging import call

worker_1 = await call(registry, ("get", "worker-1"))

If the child is currently down (or was never registered), this returns None (see Registry.handle_call()).

Supervision trees

You can build supervision trees by supervising other supervisors, since Supervisor is an Actor.

import anyio

from fauxtp.registry import Registry
from fauxtp.supervisor import Supervisor, ChildSpec, RestartStrategy


async def main():
    async with anyio.create_task_group() as tg:
        registry = await Registry.start(task_group=tg)

        await Supervisor.start(
            children=[
                ChildSpec(
                    actor=Supervisor,
                    name="subtree",
                    args=(
                        [
                            ChildSpec(actor=SomeWorker, name="w1"),
                            ChildSpec(actor=SomeWorker, name="w2"),
                        ],
                        RestartStrategy.ONE_FOR_ONE,
                        registry,
                    ),
                ),
            ],
            strategy=RestartStrategy.ONE_FOR_ALL,
            registry=registry,
            task_group=tg,
        )


anyio.run(main)

Tip: passing the same registry PID down the tree lets you resolve names from a single place.

What this supervisor does not do (yet)

This supervisor is intentionally small. It currently does not implement: