Skip to main content

ActorRef

Struct ActorRef 

Source
pub struct ActorRef<T: Actor> { /* private fields */ }
Expand description

A type-safe reference to an actor of type T.

ActorRef<T> provides type-safe message passing to actors, ensuring that only messages that the actor can handle are sent, and that reply types are correctly typed. It provides compile-time type safety through Rust’s type system and trait bounds.

§Type Safety Benefits

  • Compile-Time Message Validation: Only messages implementing Message<M> for actor T are accepted
  • Automatic Reply Type Inference: Return types are inferred from trait implementations
  • Zero Runtime Overhead: Type safety is enforced at compile time with no performance cost
  • IDE Support: Full autocomplete and type checking support
  • Prevention of Runtime Type Errors: Eliminates downcasting failures and type mismatches

§Message Passing Methods

  • Asynchronous Methods:

    • ask: Send a message and await a typed reply.
    • ask_with_timeout: Send a message and await a typed reply with a timeout.
    • tell: Send a message without waiting for a reply.
    • tell_with_timeout: Send a message without waiting for a reply with a timeout.
  • Blocking Methods:

    • blocking_ask: Send a message and block until a typed reply is received (no runtime context required).
    • blocking_tell: Send a message and block until it is sent (no runtime context required).
    • ask_blocking: (Deprecated) Send a message and block until a typed reply is received.
    • tell_blocking: (Deprecated) Send a message and block until it is sent.

    The new blocking_* methods use Tokio’s underlying blocking_send and blocking_recv and can be used from any thread.

  • Control Methods:

    • stop: Gracefully stop the actor.
    • kill: Immediately terminate the actor.
  • Utility Methods:

    • identity: Get the unique ID of the actor.
    • is_alive: Check if the actor is still running.
    • ask_join: Send a message expecting a JoinHandle and await its completion.

Use ActorRef<T> by default for all actor communication. It provides compile-time guarantees that prevent type-related runtime errors.

When to use ActorRef<T>:

  • Default choice for actor communication
  • When you know the actor type at compile time
  • When you want compile-time message validation
  • When working with strongly-typed actor systems

Implementations§

Source§

impl<T: Actor> ActorRef<T>

Source

pub fn identity(&self) -> Identity

Returns the unique ID of the actor.

Source

pub fn is_alive(&self) -> bool

Checks if the actor is still alive by verifying if its channels are open.

Source

pub fn downgrade(this: &Self) -> ActorWeak<T>

Creates a weak, type-safe reference to this actor.

The returned ActorWeak<T> can be used to check if the actor is still alive and optionally upgrade back to a strong ActorRef<T> without keeping the actor alive. When the metrics feature is enabled, metrics are preserved via strong reference for post-mortem analysis.

Source

pub async fn tell<M>(&self, msg: M) -> Result<()>
where M: Send + 'static, T: Message<M>,

Sends a message to the actor without awaiting a reply (fire-and-forget).

The message is sent to the actor’s mailbox for processing. This method returns immediately.

Type safety: Only messages that the actor T can handle via Message<M> trait are accepted.

Source

pub async fn tell_with_timeout<M>( &self, msg: M, timeout: Duration, ) -> Result<()>
where T: Message<M>, M: Send + 'static,

Sends a message to the actor without awaiting a reply (fire-and-forget) with a timeout.

Similar to ActorRef::tell, but allows specifying a timeout for the send operation. The message is sent to the actor’s mailbox, and this method will return once the message is sent or timeout if the send operation doesn’t complete within the specified duration.

Source

pub async fn ask<M>(&self, msg: M) -> Result<T::Reply>
where T: Message<M>, M: Send + 'static, T::Reply: Send + 'static,

Sends a message to the actor and awaits a reply.

The message is sent to the actor’s mailbox, and this method will wait for the actor to process the message and send a reply.

Type safety: The return type R is automatically inferred from the Message<M> trait implementation, ensuring compile-time type safety for replies.

Source

pub async fn ask_with_timeout<M>( &self, msg: M, timeout: Duration, ) -> Result<T::Reply>
where T: Message<M>, M: Send + 'static, T::Reply: Send + 'static,

Sends a message to the actor and awaits a reply with a timeout.

Similar to ActorRef::ask, but allows specifying a timeout for the operation. The message is sent to the actor’s mailbox, and this method will wait for the actor to process the message and send a reply, or timeout if the reply doesn’t arrive within the specified duration.

Source

pub fn kill(&self) -> Result<()>

Sends an immediate termination signal to the actor.

The actor will stop processing messages and shut down as soon as possible. The actor’s final result will indicate it was killed.

Source

pub async fn stop(&self) -> Result<()>

Sends a graceful stop signal to the actor.

The actor will process all messages currently in its mailbox and then stop. New messages sent after this call might be ignored or fail. The actor’s final result will indicate normal completion.

Source

pub fn blocking_tell<M>(&self, msg: M, timeout: Option<Duration>) -> Result<()>
where M: Send + 'static, T: Message<M>,

Synchronous version of ActorRef::tell that blocks until the message is sent.

This method can be used from any thread, including non-async contexts. It does not require a Tokio runtime context.

§Timeout Behavior
  • timeout: None: Uses Tokio’s blocking_send directly. This is the most efficient option but will block indefinitely if the mailbox is full.

  • timeout: Some(duration): Spawns a separate thread with a temporary Tokio runtime to handle the timeout. This approach has additional overhead but guarantees the call will return within the specified duration.

§Performance Considerations

When using a timeout, this method incurs the following overhead:

  • Thread creation: ~50-200μs depending on the platform
  • Tokio runtime creation: ~1-10μs for a single-threaded runtime
  • Channel synchronization: Minimal overhead for result passing

For performance-critical code paths where timeout is not required, pass None to avoid this overhead. The timeout variant is designed for scenarios where bounded waiting is more important than raw performance.

§Thread Safety

This method is safe to call from within an existing Tokio runtime context because the timeout implementation spawns a separate thread with its own runtime, avoiding the “cannot start a runtime from within a runtime” panic.

Source

pub fn blocking_ask<M>( &self, msg: M, timeout: Option<Duration>, ) -> Result<T::Reply>
where T: Message<M>, M: Send + 'static, T::Reply: Send + 'static,

Synchronous version of ActorRef::ask that blocks until the reply is received.

This method can be used from any thread, including non-async contexts. It does not require a Tokio runtime context.

§Timeout Behavior
  • timeout: None: Uses Tokio’s blocking_send and blocking_recv directly. This is the most efficient option but will block indefinitely if the actor never responds.

  • timeout: Some(duration): Spawns a separate thread with a temporary Tokio runtime to handle the timeout. This approach has additional overhead but guarantees the call will return within the specified duration.

§Performance Considerations

When using a timeout, this method incurs the following overhead:

  • Thread creation: ~50-200μs depending on the platform
  • Tokio runtime creation: ~1-10μs for a single-threaded runtime
  • Channel synchronization: Minimal overhead for result passing

For performance-critical code paths where timeout is not required, pass None to avoid this overhead. The timeout variant is designed for scenarios where bounded waiting is more important than raw performance.

§Thread Safety

This method is safe to call from within an existing Tokio runtime context because the timeout implementation spawns a separate thread with its own runtime, avoiding the “cannot start a runtime from within a runtime” panic.

Source

pub fn tell_blocking<M>(&self, msg: M, timeout: Option<Duration>) -> Result<()>
where T: Message<M>, M: Send + 'static,

👎Deprecated since 0.10.0: Use blocking_tell instead. Timeout parameter is ignored.

Synchronous version of ActorRef::tell that blocks until the message is sent.

This method is intended for use within tokio::task::spawn_blocking contexts.

Deprecated: Use blocking_tell instead. The timeout parameter is ignored.

Source

pub fn ask_blocking<M>( &self, msg: M, timeout: Option<Duration>, ) -> Result<T::Reply>
where T: Message<M>, M: Send + 'static, T::Reply: Send + 'static,

👎Deprecated since 0.10.0: Use blocking_ask instead. Timeout parameter is ignored.

Synchronous version of ActorRef::ask that blocks until the reply is received.

This method is intended for use within tokio::task::spawn_blocking contexts.

Deprecated: Use blocking_ask instead. The timeout parameter is ignored.

Source

pub async fn ask_join<M, R>(&self, msg: M) -> Result<R>
where T: Message<M, Reply = JoinHandle<R>>, M: Send + 'static, R: Send + 'static,

Sends a message to an actor expecting a JoinHandle reply and awaits its completion.

This method is specifically designed for the pattern where message handlers spawn long-running asynchronous tasks using tokio::spawn and return the JoinHandle. Instead of manually handling the JoinHandle, this method automatically awaits the spawned task and returns the final result.

§Common Pattern

This method supports the following actor pattern:

use rsactor::{Actor, ActorRef, message_handlers};
use tokio::task::JoinHandle;
use std::time::Duration;

#[derive(Actor)]
struct WorkerActor;

struct HeavyTask {
    data: String,
}

#[message_handlers]
impl WorkerActor {
    #[handler]
    async fn handle_heavy_task(
        &mut self,
        msg: HeavyTask,
        _: &ActorRef<Self>
    ) -> JoinHandle<String> {
        let data = msg.data.clone();
        // Spawn a long-running task to avoid blocking the actor
        tokio::spawn(async move {
            tokio::time::sleep(Duration::from_secs(5)).await;
            format!("Processed: {}", data)
        })
    }
}
§Usage Examples

See the examples/ask_join_demo.rs file for a complete working example that demonstrates:

  • Handlers that return JoinHandle<T> from spawned tasks
  • Using ask_join vs regular ask with manual await
  • Error handling for panicked and cancelled tasks
  • Concurrent task execution patterns
§Error Handling

This method can return errors in several scenarios:

The Error::Join variant includes the original tokio::task::JoinError which provides detailed information about task failures, such as whether the task was cancelled or panicked.

§Type Safety

This method enforces compile-time type safety:

  • The message type M must be handled by actor T
  • The handler must return tokio::task::JoinHandle<R>
  • The final return type R is automatically inferred and type-checked

Trait Implementations§

Source§

impl<T: Actor + 'static> ActorControl for ActorRef<T>

Source§

fn identity(&self) -> Identity

Returns the unique identity of the actor.
Source§

fn is_alive(&self) -> bool

Checks if the actor is still alive.
Source§

fn stop(&self) -> BoxFuture<'_, Result<()>>

Gracefully stops the actor. Read more
Source§

fn kill(&self) -> Result<()>

Immediately terminates the actor. Read more
Source§

fn downgrade(&self) -> Box<dyn WeakActorControl>

Downgrades to a weak control reference.
Source§

fn clone_boxed(&self) -> Box<dyn ActorControl>

Clone this control into a new boxed instance.
Source§

fn debug_fmt(&self, f: &mut Formatter<'_>) -> Result

Debug formatting support for trait objects.
Source§

impl<T, M> AskHandler<M, <T as Message<M>>::Reply> for ActorRef<T>
where T: Actor + Message<M> + 'static, M: Send + 'static, <T as Message<M>>::Reply: Send + 'static,

Source§

fn ask(&self, msg: M) -> BoxFuture<'_, Result<<T as Message<M>>::Reply>>

Sends a message and awaits a reply.
Source§

fn ask_with_timeout( &self, msg: M, timeout: Duration, ) -> BoxFuture<'_, Result<<T as Message<M>>::Reply>>

Sends a message and awaits a reply with timeout.
Source§

fn blocking_ask( &self, msg: M, timeout: Option<Duration>, ) -> Result<<T as Message<M>>::Reply>

Blocking version of ask. Read more
Source§

fn clone_boxed(&self) -> Box<dyn AskHandler<M, <T as Message<M>>::Reply>>

Clone this handler into a new boxed instance.
Source§

fn downgrade(&self) -> Box<dyn WeakAskHandler<M, <T as Message<M>>::Reply>>

Downgrade to a weak handler.
Source§

fn as_control(&self) -> &dyn ActorControl

Returns a reference to ActorControl for lifecycle management. Read more
Source§

fn debug_fmt(&self, f: &mut Formatter<'_>) -> Result

Debug formatting support for trait objects.
Source§

impl<T: Actor> Clone for ActorRef<T>

Source§

fn clone(&self) -> Self

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl<T: Debug + Actor> Debug for ActorRef<T>

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl<T: Actor + 'static> From<&ActorRef<T>> for Box<dyn ActorControl>

Source§

fn from(actor_ref: &ActorRef<T>) -> Self

Converts to this type from the input type.
Source§

impl<T, M> From<&ActorRef<T>> for Box<dyn AskHandler<M, <T as Message<M>>::Reply>>
where T: Actor + Message<M> + 'static, M: Send + 'static, <T as Message<M>>::Reply: Send + 'static,

Source§

fn from(actor_ref: &ActorRef<T>) -> Self

Converts to this type from the input type.
Source§

impl<T, M> From<&ActorRef<T>> for Box<dyn TellHandler<M>>
where T: Actor + Message<M> + 'static, M: Send + 'static,

Source§

fn from(actor_ref: &ActorRef<T>) -> Self

Converts to this type from the input type.
Source§

impl<T: Actor + 'static> From<ActorRef<T>> for Box<dyn ActorControl>

Source§

fn from(actor_ref: ActorRef<T>) -> Self

Converts to this type from the input type.
Source§

impl<T, M> From<ActorRef<T>> for Box<dyn AskHandler<M, <T as Message<M>>::Reply>>
where T: Actor + Message<M> + 'static, M: Send + 'static, <T as Message<M>>::Reply: Send + 'static,

Source§

fn from(actor_ref: ActorRef<T>) -> Self

Converts to this type from the input type.
Source§

impl<T, M> From<ActorRef<T>> for Box<dyn TellHandler<M>>
where T: Actor + Message<M> + 'static, M: Send + 'static,

Source§

fn from(actor_ref: ActorRef<T>) -> Self

Converts to this type from the input type.
Source§

impl<T, M> TellHandler<M> for ActorRef<T>
where T: Actor + Message<M> + 'static, M: Send + 'static,

Source§

fn tell(&self, msg: M) -> BoxFuture<'_, Result<()>>

Sends a message without waiting for a reply.
Source§

fn tell_with_timeout( &self, msg: M, timeout: Duration, ) -> BoxFuture<'_, Result<()>>

Sends a message with timeout.
Source§

fn blocking_tell(&self, msg: M, timeout: Option<Duration>) -> Result<()>

Blocking version of tell. Read more
Source§

fn clone_boxed(&self) -> Box<dyn TellHandler<M>>

Clone this handler into a new boxed instance.
Source§

fn downgrade(&self) -> Box<dyn WeakTellHandler<M>>

Downgrade to a weak handler.
Source§

fn as_control(&self) -> &dyn ActorControl

Returns a reference to ActorControl for lifecycle management. Read more
Source§

fn debug_fmt(&self, f: &mut Formatter<'_>) -> Result

Debug formatting support for trait objects.

Auto Trait Implementations§

§

impl<T> Freeze for ActorRef<T>

§

impl<T> RefUnwindSafe for ActorRef<T>

§

impl<T> Send for ActorRef<T>

§

impl<T> Sync for ActorRef<T>

§

impl<T> Unpin for ActorRef<T>

§

impl<T> UnwindSafe for ActorRef<T>

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more