actix 0.3.5

Actor framework for Rust
docs.rs failed to build actix-0.3.5
Please check the build logs for more information.
See Builds for ideas on how to fix a failed build, or Metadata for how to configure docs.rs builds.
If you believe this is docs.rs' fault, open an issue.
Visit the last successful build: actix-0.13.3

Actix Build Status Build status codecov crates.io

Actix is a rust actor system framework.


Features

  • Typed messages (No Any type). Generic messages are allowed.
  • Async/Sync actors.
  • Actor communication in a local/thread context.
  • Using Futures for asynchronous message handling.
  • HTTP1/HTTP2 support (actix-web)
  • Actor supervision.

Usage

To use actix, add this to your Cargo.toml:

[dependencies]
actix = "0.3"

You may consider to check chat example.

Initialize the Actix

In order to use actix you first need to create an System.

extern crate actix;

fn main() {
    let system = actix::System::new("test");
    
    system.run();
}

Actix uses tokio event loop. System::new() call creates new event loop and starts System actor. system.run() starts tokio event loop and will finish once the System actor receives SystemExit message.

Let's create simple Actor.

Implement an Actor

In order to define an actor you need to define a struct and have it implement the Actor trait.

extern crate actix;
use actix::{msgs, Actor, Address, Arbiter, Context, System};

struct MyActor;

impl Actor for MyActor {
    type Context = Context<Self>;

    fn started(&mut self, ctx: &mut Self::Context) {
       println!("I am alive!");
       Arbiter::system().send(msgs::SystemExit(0));
    }
}

fn main() {
    let system = System::new("test");

    let addr: Address<_> = MyActor.start();

    system.run();
}

Spawning a new actor is achieved via the start and create methods of Actor trait. It provides several different ways of creating actors, for details check docs. You can implement started, stopping and stoppedmthods of Actor trait, started method get called when actor starts and stopping when actor finishes. Check api documentation for more information on actor lifecycle.

Handle messages

An Actor communicates with another Actor by sending an messages. In actix all messages are typed. Let's define simple Sum message with two usize parameters and actor which will accept this message and return sum of those two numbers.

extern crate actix;
extern crate futures;
use futures::{future, Future};
use actix::*;

// this is our Message
struct Sum(usize, usize);

// we have to define type of response for `Sum` message
impl ResponseType for Sum {
    type Item = usize;
    type Error = ();
}

// Actor definition
struct Summator;

impl Actor for Summator {
    type Context = Context<Self>;
}

// now we need to define `MessageHandler` for `Sum` message.
impl Handler<Sum> for Summator {

    fn handle(&mut self, msg: Sum, ctx: &mut Context<Self>) -> Response<Self, Sum> {
        Self::reply(msg.0 + msg.1)
    }
}

fn main() {
    let system = System::new("test");

    let addr: Address<_> = Summator.start();

    // Address<A>::call() returns ActorFuture object, so we need to wait for result.
    // ActorFuture makes sense within Actor execution context, but we can use
    // Address<A>::call_fut() which return simple Future object.
    let res = addr.call_fut(Sum(10, 5));
    
    system.handle().spawn(res.then(|res| {
        match res {
            Ok(Ok(result)) => println!("SUM: {}", result),
            _ => println!("Something wrong"),
        }
        
        Arbiter::system().send(msgs::SystemExit(0));
        future::result(Ok(()))
    }));

    system.run();
}

All communications with actors go through Address object. You can send message without waiting response or call actor with specific message. ResponseType trait defines response type for a message, Item and Error for value and error respectevily. There are different types of addresses. Address<A> is an address of an actor that runs in same arbiter (event loop). If actor is running in different thread SyncAddress<A> has to be used.

Actor state and subscription for specific message

If you noticed, methods of Actor and Handler traits accept &mut self, so you are welcome to store anything in an actor and mutate it whenever you need.

Address object requires actor type, but if we just want to send specific message to an actor that can handle message, we can use Subscriber interface. Let's create new actor that uses Subscriber, also this example will show how to use standard future objects. Also in this example we are going to use unstable proc_macro rust's feature for message and handler definitions

#![feature(proc_macro)]

extern crate actix;
use std::time::Duration;
use actix::*;

#[msg]
struct Ping { pub id: usize }

// Actor definition
struct Game {
    counter: usize, 
    addr: Box<Subscriber<Ping>>
}

#[actor(Context<_>)]
impl Game {

    #[simple(Ping)]
    // simple message handler for Ping message
    fn ping(&mut self, id: usize, ctx: &mut Context<Self>) {
        self.counter += 1;
        
        if self.counter > 10 {
            Arbiter::system().send(msgs::SystemExit(0));
        } else {
            println!("Ping received {:?}", id);
            
            // wait 100 nanos
            ctx.run_later(Duration::new(0, 100), move |act, _| {
                act.addr.send(Ping{id: id + 1});
            });
        }
    }
}

fn main() {
    let system = System::new("test");

    // we need Subscriber object so we need to use different builder method
    // which will allow to postpone actor creation
    let _: Address<_> = Game::create(|ctx| {
        // now we can get address of first actor and create second actor
        let addr: Address<_> = ctx.address();
        let addr2: Address<_> = Game{counter: 0, addr: addr.subscriber()}.start();
        
        // lets start pings
        addr2.send(Ping{id: 10});
        
        // now we can finally create first actor
        Game{counter: 0, addr: addr2.subscriber()}
    });

    system.run();
}

More information on signals handling is in signal module.

chat example

You may consider to check chat example. It provides basic example of networking client/server service.

fectl

You may consider to check fectl utility. It is written with actix and shows how to create networking application with relatevly complex interactions.

Contributing

All contribution are welcome, if you have a feature request don't hesitate to open an issue!

License

This project is licensed under either of

at your option.