actix

by actix

actix / actix

Actor framework for Rust.

5.7K Stars 511 Forks Last release: about 1 month ago (v0.10.0) Other 896 Commits 49 Releases

Available items

No Items, yet!

The developer of this repository has not created any items for sale yet. Need a bug fixed? Help with integration? A different license? Create a request here:

Actix

Actor framework for Rust

crates.io Documentation Version
License codecov Download Join the chat at https://gitter.im/actix/actix

| Platform | Build Status | | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- | | Linux | build status | | macOS | build status | | Windows | build status |


Features

  • Async and sync actors
  • Actor communication in a local/thread context
  • Uses futures for asynchronous message handling
  • Actor supervision
  • Typed messages (No
    Any
    type)
  • Runs on stable Rust 1.40+

Usage

To use

actix
, add this to your
Cargo.toml
:
[dependencies]
actix = "0.10"

Initialize Actix

In order to use actix you first need to create a

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

system.run();

}

Actix uses the tokio event loop.

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

Let's create a simple Actor.

Implement an Actor

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

Actor
trait.

use actix::{Actor, Addr, Arbiter, Context, System};

struct MyActor;

impl Actor for MyActor { type Context = Context;

fn started(&mut self, ctx: &mut Self::Context) {
    println!("I am alive!");
    System::current().stop(); // 

Spawning a new actor is achieved via the

start
and
create
methods of the Actor trait. It provides several different ways of creating actors, for details check docs. You can implement
started
,
stopping
and
stopped
methods of the Actor trait.
started
gets called when actor starts and
stopping
when actor finishes. Check API documentation for more information on the actor lifecycle.

Handle Messages

An Actor communicates with another Actor by sending messages. In actix all messages are typed. Let's define a simple

Sum
message with two
usize
parameters, and an actor which will accept this message and return the sum of those two numbers. Here we use the actix-rt as way start our
System
and drive our main
Future
so we can easily
.await
for the messages sent to the
Actor
.
use actix::prelude::*;

// this is our Message #[derive(Message)] #[rtype(result = "usize")] // we have to define the response type for Sum message struct Sum(usize, usize);

// Actor definition struct Summator;

impl Actor for Summator { type Context = Context; }

// now we need to define MessageHandler for the Sum message. impl Handler for Summator { type Result = usize; // ) -> Self::Result { msg.0 + msg.1 } }

#[actix_rt::main] // println!("SUM: {}", result), _ => println!("Communication to the actor has failed"), } }

All communications with actors go through an

Addr
object. You can
do_send
a message without waiting for a response, or
send
an actor with specific message. The
Message
trait defines the result type for a message.

Actor State And Subscription For Specific Messages

You may have noticed that methods of

Actor
and
Handler
traits accept
&mut self
, so you are welcome to store anything in an actor and mutate it whenever necessary.

Address objects require an actor type, but if we just want to send a specific message to an actor that can handle the message, we can use the

Recipient
interface. Let's create a new actor that uses
Recipient
.
use actix::prelude::*;
use std::time::Duration;

#[derive(Message)] #[rtype(result = "()")] struct Ping { pub id: usize, }

// Actor definition struct Game { counter: usize, name: String, addr: Recipient, }

impl Actor for Game { type Context = Context; }

// simple message handler for Ping message impl Handler for Game { type Result = ();

fn handle(&amp;mut self, msg: Ping, ctx: &amp;mut Context<self>) {
    self.counter += 1;

    if self.counter &gt; 10 {
        System::current().stop();
    } else {
        println!("[{0}] Ping received {1}", self.name, msg.id);

        // wait 100 nanoseconds
        ctx.run_later(Duration::new(0, 100), move |act, _| {
            act.addr.do_send(Ping { id: msg.id + 1 });
        });
    }
}

}

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

// To get a Recipient object, we need to use a different builder method
// which will allow postponing actor creation
let addr = Game::create(|ctx| {
    // now we can get an address of the first actor and create the second actor
    let addr = ctx.address();
    let addr2 = Game {
        counter: 0,
        name: String::from("Game 2"),
        addr: addr.recipient(),
    }
    .start();

    // let's start pings
    addr2.do_send(Ping { id: 10 });

    // now we can finally create first actor
    Game {
        counter: 0,
        name: String::from("Game 1"),
        addr: addr2.recipient(),
    }
});

system.run();

}

Chat Example

There is a chat example which provides a basic example of networking client/server service.

Contributing

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

License

This project is licensed under either of

  • Apache License, Version 2.0, (LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0)
  • MIT license (LICENSE-MIT or https://opensource.org/licenses/MIT)

at your option.

Code of Conduct

Contribution to the actix crate is organized under the terms of the Contributor Covenant, the maintainers of actix, promises to intervene to uphold that code of conduct.

We use cookies. If you continue to browse the site, you agree to the use of cookies. For more information on our use of cookies please see our Privacy Policy.