Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

compio-actor

An actor framework for Compio.

The interface is centered on a few types:

  • Actor owns state and lifecycle hooks.
  • Handler<M> adds each message type an actor accepts.
  • Cluster places actors on runtimes managed by compio-dispatcher.
  • Mailbox<A> casts any M for which A: Handler<M>.
  • Broker<M> is a send-only capability derived from an actor reference.
  • ActorHandle<E> observes completion without cancelling the actor when dropped.

Actors, their state, and their futures stay on one worker and do not need to implement Send. Actor factories, messages, references, startup arguments, and errors can cross threads and therefore must be Send. Calling stop lets the current handler finish. The lifecycle order is pre_start, post_start, message handling, pre_stop, then post_stop.

An actor can implement multiple Handler<M: Message>. Different message types share one bounded FIFO mailbox. Messages and their worker-local handler futures are type-erased internally, so each handled message currently requires two small allocations.

Example

use std::{convert::Infallible, io};

use compio_actor::{Actor, ActorExit, Broker, Cluster, Handler, Mailbox};

struct Counter;

#[derive(Debug)]
struct Add(usize);

#[derive(Debug)]
struct Stop;

impl Actor for Counter {
    type State = usize;
    type Arguments = usize;
    type Error = Infallible;

    async fn pre_start(
        &self,
        _myself: &Mailbox<Self>,
        initial: usize,
    ) -> Result<usize, Infallible> {
        Ok(initial)
    }
}

impl Handler<Add> for Counter {
    async fn handle(
        &self,
        _: &Mailbox<Self>,
        Add(value): Add,
        state: &mut usize,
    ) -> Result<(), Infallible> {
        *state += value;
        Ok(())
    }
}

impl Handler<Stop> for Counter {
    async fn handle(
        &self,
        myself: &Mailbox<Self>,
        Stop: Stop,
        state: &mut usize,
    ) -> Result<(), Infallible> {
        assert_eq!(*state, 5);
        myself.stop();
        Ok(())
    }
}

fn main() -> io::Result<()> {
    compio_runtime::Runtime::new()?.block_on(async {
        // `Cluster` will spin up a thread pool upon creating
        let cluster = Cluster::new()?;

        // Spawn an actor in the thread pool. Notice that actors doesn't need to be movable.
        // They stay on the thread where they were created. Only messages and args are.
        let (counter, handle) = cluster.spawn(|| Counter, 0).await.unwrap();

        // Use broker to send a message without knowing what the underlying actor is
        let add: Broker<Add> = counter.broker();
        add.send(Add(2)).unwrap();
        counter.send(Add(3)).unwrap();
        counter.send(Stop).unwrap();

        // Use handle to retrieve the final result
        assert_eq!(handle.await.unwrap(), ActorExit::Stopped);
        cluster.join().await
    })
}

About

An actor framework for compio

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages