Rate this Page
bootstrap_canonical_simple">

Appendix: bootstrap_canonical_simple#

This is the exact test from the codebase that the walkthrough above is unpacking.

// from hyperactor_mesh/src/bootstrap.rs (tests)
#[tokio::test]
async fn bootstrap_canonical_simple() {
    // SAFETY: unit-test scoped
    unsafe {
        std::env::set_var("HYPERACTOR_MESH_BOOTSTRAP_ENABLE_PDEATHSIG", "false");
    }

    // 1) Create a "root" direct-addressed proc.
    let proc = Proc::direct(ChannelTransport::Unix.any(), "root".to_string())
        .await
        .unwrap();

    // 2) Create an actor instance we'll use to send and receive messages.
    let (instance, _handle) = proc.instance("client").unwrap();

    // 3) Configure a ProcessAllocator with the bootstrap binary.
    let mut allocator = ProcessAllocator::new(Command::new(crate::testresource::get(
        "monarch/hyperactor_mesh/bootstrap",
    )));

    // 4) Request a new allocation of procs from the ProcessAllocator.
    let alloc = allocator
        .allocate(AllocSpec {
            extent: extent!(replicas = 1),
            constraints: Default::default(),
            proc_name: None,
            transport: ChannelTransport::Unix,
        })
        .await
        .unwrap();

    // 5) Build a HostMesh with explicit OS-process boundaries (per rank):
    //
    // (1) Allocator → bootstrap proc [OS process #1]
    //     `ProcMesh::allocate(..)` starts one OS process per
    //     rank; each runs our runtime and the trampoline actor.
    //
    // (2) Host::serve(..) sets up a Host in the same OS process
    //     (no new process). It binds front/back channels, creates
    //     an in-process service proc (`Proc::new(..)`), and
    //     stores the `BootstrapProcManager` for later spawns.
    //
    // (3) Install HostAgent (still no new OS process).
    //     `host.system_proc().spawn::<HostAgent>("host_agent",
    //     host).await?` creates the HostAgent actor in that
    //     service proc.
    //
    // (4) Collect & assemble. The trampoline returns a
    //     direct-addressed `ActorRef<HostAgent>`; we collect
    //     one per rank and assemble a `HostMesh`.
    //
    // Note: When the Host is later asked to start a proc
    // (`host.spawn(name)`), it calls `ProcManager::spawn` on the
    // stored `BootstrapProcManager`, which does a
    // `Command::spawn()` to launch a new OS child process for
    // that proc.
    let host_mesh = HostMesh::allocate(&instance, Box::new(alloc), "test", None)
        .await
        .unwrap();

    // 6) Spawn a ProcMesh named "p0" on the host mesh:
    //
    // (1) Each HostAgent (running inside its host's service
    //     proc) receives the request.
    //
    // (2) The Host calls into its `BootstrapProcManager::spawn`,
    //     which does `Command::spawn()` to launch a brand-new OS
    //     process for the proc.
    //
    // (3) Inside that new process, bootstrap runs and a
    //     `ProcAgent` is started to manage it.
    //
    // (4) We collect the per-host procs into a `ProcMesh` and
    //     return it.
    let proc_mesh = host_mesh
        .spawn(&instance, "p0", Extent::unity())
        .await
        .unwrap();

    // 7) Spawn an ActorMesh<TestActor> named "a0" on the proc mesh:
    //
    // (1) For each proc (already running in its own OS process),
    //     the `ProcAgent` receives the request.
    //
    // (2) It spawns a `TestActor` inside that existing proc (no
    //     new OS process).
    //
    // (3) The per-proc actors are collected into an
    //     `ActorMesh<TestActor>` and returned.
    let actor_mesh: ActorMesh<testactor::TestActor> =
        proc_mesh.spawn(&instance, "a0", &()).await.unwrap();

    // 8) Open a fresh port on the client instance and send a
    //    GetActorId message to the actor mesh. Each TestActor will
    //    reply with its actor ID to the bound port. Receive one
    //    reply and assert it matches the ID of the (single) actor in
    //    the mesh.
    let (port, mut rx) = instance.mailbox().open_port();
    actor_mesh
        .cast(&instance, testactor::GetActorId(port.bind()))
        .unwrap();
    let got_id = rx.recv().await.unwrap();
    assert_eq!(
        got_id,
        actor_mesh.values().next().unwrap().actor_id().clone()
    );

    // 9) Important: shut down, or we'll leak the OS children the hosts spawned.
    host_mesh.shutdown(&instance).await.expect("host shutdown");
}