ActorHandle<A>
#
An ActorHandle<A>
is a reference to a local, running actor of type A
. It provides access to the actor’s messaging ports, lifecycle status, and control methods (such as stop signals).
Unlike remote references (e.g. ActorRef<A>
), which may refer to actors on other Proc
s, an ActorHandle
only exists within the same Proc
and can be sent messages without requiring serialization.
Definition#
pub struct ActorHandle<A: Actor> {
cell: InstanceCell,
ports: Arc<Ports<A>>,
}
An ActorHandle
contains:
cell
is the actor’s internal runtime state, including identity and lifecycle metadata.ports
is a shared dictionary of all typed message ports available to the actor.
This handle is cloneable, sendable across tasks, and allows interaction with the actor via messaging, status observation, and controlled shutdown.
Methods#
new
(internal)#
Constructs a new ActorHandle
from its backing InstanceCell
and Ports
. This is called by the runtime when spawning a new actor.
pub(crate) fn new(cell: InstanceCell, ports: Arc<Ports<A>>) -> Self {
Self { cell, ports }
}
cell
(internal)#
Returns the underlying InstanceCell
backing the actor.
pub(crate) fn cell(&self) -> &InstanceCell {
&self.cell
}
actor_id
#
Returns the ActorId
of the actor represented by this handle.
pub fn actor_id(&self) -> &ActorId {
self.cell.actor_id()
}
drain_and_stop
#
Signals the actor to drain any pending messages and then stop. This enables a graceful shutdown procedure.
pub fn drain_and_stop(&self) -> Result<(), ActorError> {
self.cell.signal(Signal::DrainAndStop)
}
status
#
Returns a watch channel that can be used to observe the actor’s lifecycle status (e.g., running, stopped, crashed).
pub fn status(&self) -> watch::Receiver<ActorStatus> {
self.cell.status().clone()
}
send
#
Sends a message of type M
to the actor. The actor must implement Handler<M>
for this to compile.
Messages sent via an ActorHandle
are always delivered in-process and do not require serialization.
pub fn send<M: Message>(&self, message: M) -> Result<(), MailboxSenderError>
where
A: Handler<M>,
{
self.ports.get().send(message)
}
port
#
Returns a reusable port handle for the given message type.
pub fn port<M: Message>(&self) -> PortHandle<M>
where
A: Handler<M>,
{
self.ports.get()
}
bind
#
Creates a remote reference (ActorRef<R>
) by applying a Binds<A>
implementation.
pub fn bind<R: Binds<A>>(&self) -> ActorRef<R> {
self.cell.bind(self.ports.as_ref())
}
Binding and ActorRefs#
The bind()
method on ActorHandle
creates an ActorRef<R>
for a given remote-facing reference type R
. This is the bridge between a local actor instance and its externally visible interface.
pub fn bind<R: Binds<A>>(&self) -> ActorRef<R>
This method requires that R
implements the Binds<A>
trait. The Binds
trait specifies how to associate a remote-facing reference type with the concrete ports handled by the actor:
pub trait Binds<A: Actor>: RemoteActor {
fn bind(ports: &Ports<A>);
}
In practice, A
and R
are usually the same type; this is the pattern produced by the #[export]
macro. But R
can also be a trait object or wrapper that abstracts over multiple implementations.
Binding internals#
Calling bind()
on the ActorHandle
:
Invokes the
Binds<A>::bind()
implementation forR
, registering the actor’s message handlers into thePorts<A>
dictionary.Always binds the
Signal
type (used for draining, stopping, and supervision).Records the bound message types into
InstanceState::exported_named_ports
, enabling routing and diagnostics.Constructs the final
ActorRef<R>
usingActorRef::attest(...)
, which assumes the type-level correspondence betweenR
and the bound ports.
The result is a typed, routable reference that can be shared across Proc
s.
IntoFuture for ActorHandle
#
Overview#
An ActorHandle<A>
can be awaited directly thanks to its IntoFuture
implementation. Awaiting the handle
waits for the actor to shut down.
Purpose#
This allows you to write:
let status = actor_handle.await;
Instead of:
let mut status = actor_handle.status();
status.wait_for(ActorStatus::is_terminal).await;
Behavior#
When awaited, the handle:
Subscribes to the actor’s status channel,
Waits for a terminal status (
Stopped
,Crashed
, etc.),Returns the final status,
Returns
ActorStatus::Unknown
if the channel closes unexpectedly.
Implementation#
impl<A: Actor> IntoFuture for ActorHandle<A> {
type Output = ActorStatus;
type IntoFuture = BoxFuture<'static, Self::Output>;
fn into_future(self) -> Self::IntoFuture {
let future = async move {
let mut status_receiver = self.cell.status().clone();
let result = status_receiver.wait_for(ActorStatus::is_terminal).await;
match result {
Err(_) => ActorStatus::Unknown,
Ok(status) => status.passthrough(),
}
};
future.boxed()
}
}
Summary#
This feature is primarily ergonomic. It provides a natural way to synchronize with the termination of an actor by simply awaiting its handle.