Rate this Page

Proc#

A Proc is the fundamental container for actors in hyperactor. It provides the runtime context for actor execution and determines how messages are routed—both inbound messages arriving at the proc from the network and outbound messages leaving the proc.

Construction#

Create a proc using Proc::new():

pub fn new(proc_id: ProcId, forwarder: BoxedMailboxSender) -> Self

Parameters:

  • proc_id: The proc’s unique identity (see ProcId)

  • forwarder: A BoxedMailboxSender that routes all outbound messages from this proc

The forwarder is the critical routing component for remote delivery - when an actor within this proc sends a message to an actor in another proc, it flows through this forwarder.

Example: Service Proc in Host#

From Host::new():

let router = DialMailboxRouter::new();

let service_proc_id = ProcId::Direct(
    frontend_addr.clone(),
    "service".to_string()
);

let service_proc = Proc::new(service_proc_id, router.boxed());

Here:

  • The proc is identified by ProcId::Direct(frontend_addr, "service")

  • All outbound messages use the DialMailboxRouter as their forwarder

  • The router will look up target procs and dial their backend addresses

ProcId: Direct Addressing#

Procs are identified using ProcId::Direct:

ProcId::Direct(ChannelAddr, String)

Example:

let addr: ChannelAddr = "unix:@abc123".parse()?;
let proc_id = ProcId::Direct(addr, "service".to_string());

The proc is addressed by:

  • The host’s channel address (where it can be reached)

  • A name identifying the proc within that host

See ProcId for complete details.

Forwarder Integration#

The forwarder determines how messages leave the proc. Typically, a DialMailboxRouter is used to enable dynamic routing to multiple destinations.

Using DialMailboxRouter#

Routes messages by looking up target addresses and dialing connections:

let router = DialMailboxRouter::new();
let proc = Proc::new(proc_id, router.boxed());

When an actor sends a message to another proc, the router:

  1. Looks up the target’s address in its address book

  2. Dials a connection (or reuses a cached one)

  3. Sends the message over that connection

See Routers.

Local Proc Bypass#

When a proc sends a message to an actor in another proc, the message normally flows through the proc’s forwarder to a backend address, where a central routing layer forwards it to the destination proc (see Host for the complete architecture with frontend and backend receivers). For procs running on the same host, this can be optimized: procs can dial each other directly via Unix sockets, bypassing the central routing layer entirely.

Injection point: When a proc manager spawns a new proc, instead of providing a plain backend sender as the forwarder, it wraps it with a local-aware forwarder:

// At proc spawn time, the manager injects a local bypass forwarder:
let backend_sender = MailboxClient::dial(backend_addr);
let proc_forwarder = LocalProcDialer::new(
    host_frontend_addr,   // Identify local procs by this address
    socket_dir,           // Directory where procs place Unix sockets
    backend_sender,       // Fallback for remote procs
);
let proc = Proc::new(proc_id, proc_forwarder.boxed());

The forwarder checks each outbound message: if the destination is a local proc (matching the host’s frontend address), it dials directly via the proc’s Unix socket. Otherwise, it routes through the backend sender:

impl MailboxSender for LocalProcDialer {
    fn post_unchecked(&self, envelope: MessageEnvelope, ...) {
        if envelope.dest().proc_id() == local_proc_on_this_host {
            unix_sender.post_unchecked(envelope, ...)  // Direct
        } else {
            backend_sender.post_unchecked(envelope, ...)  // Via host backend
        }
    }
}

This improves throughput for intra-host communication by reducing message copies and preventing the host agent from becoming a sequencing bottleneck for all messages between local procs, while maintaining compatibility with remote routing.

See hyperactor_mesh::bootstrap::mailbox::LocalProcDialer for the implementation.

Spawning Actors#

Once you have a proc, spawn actors within it:

let actor_handle = proc.spawn("my_actor", MyActor::new())?;

The spawned actor:

  • Runs within this proc

  • Inherits the proc’s ProcId as part of its ActorId

  • Uses the proc’s forwarder for outbound messages

See RemoteSpawn for spawning details.

See Also#

  • Host - How hosts create and manage procs

  • ProcId - Proc addressing schemes

  • Routers - Forwarder implementations

  • ActorId - How actors inherit proc identity