class: center, middle # Actix and Actors in Rust ##### Nathan Hawkins --- # Actix Overview - Actix is a Rust library for concurrent programming that is loosely based on the actor model - Provides a framework for passing typed messages between actors - Actors may run in multiple threads - Allows synchronous and asynchronous actors to coexist and communicate by passing messages --- # Actor Model - The actor model is a conceptual model for distributed and concurrent programming - An **actor** is a thing that receives **messages** and does some computation based on them - Messages are delivered to a **mailbox**, which generally acts as a queue for the actor --- ![](actor_model.png) --- # Actor Behavior - In response to a message that it receives, an actor may: - Create more actors - Send more messages - Decide how to respond - Do internal things with the actor's own state --- # What's an Actor in Actix? - Implements the `actix::Actor` trait - Primarily this simply means handling messages - Associated with a mailbox and an address --- # Messages - A message can be any Rust type which implements the `actix::Message` trait - Which messages an actor can receive is static - An Actor has to provide a `Handler<Message>` implementation for each type of message it can receive - Messages have associated `Result` types - Mailboxes are bounded (16 messages by default) --- # Example: Ping Message ```rust use std::io; use actix::prelude::*; struct Ping; impl Message for Ping { type Result = Result<bool, io::Error>; } ``` --- # Example: Ping Actor ```rust // Define actor struct MyActor; // Provide Actor implementation for our actor impl Actor for MyActor { type Context = Context<Self>; } // Define handler for `Ping` message impl Handler<Ping> for MyActor { type Result = Result<bool, io::Error>; fn handle(&mut self, msg: Ping, ctx: &mut Context<Self>) -> Self::Result { println!("Ping received"); Ok(true) } } ``` --- # Arbiters and Contexts - Actix provides two controllers - `Arbiter` runs a Tokio event loop - Works with `Context`, which provides a Future based implementation of Actor - `SyncArbiter` runs a thread pool and multi consumer queue - Has an associated `SyncContext` --- # SyncArbiter - `SyncArbiter` runs synchronous actors on a thread pool - Only one sync actor runs within each thread - Sync actors use `SyncContext` instead of `Context` - This means actors are statically typed as either sync and async --- # So what can you do with this? - Sync and async actors can send messages between threads - Sync code can be written in simple, linear style - Async code doesn't block, it can wait on a Future - Actix makes it possible to compose sync and async code --- # Actix-Web - Async web framework built on top of Actix - Runs on stable, __does not require nightly Rust__ - Supports HTTP 1.x and 2.0 - Websockets - Transparent compression - SSL - Request routing - Middlewares --- # Actix-Web Hello World ```rust extern crate actix_web; use actix_web::{App, HttpServer, Path}; fn index(info: Path<(String, u32)>) -> String { format!("Hello {}! id:{}", info.0, info.1) } fn main() { HttpServer::new( || App::new() .resource("/{name}/{id}/index.html", |r| r.with(index))) .bind("127.0.0.1:8080").unwrap() .run(); } ``` --- # Actix-Web is an Actor - `actix_web::HttpServer` is an Actix Actor - HTTP request handlers can be async functions, or can be Actors themselves - Web applications can be embedded within larger systems of Actors - Other components, such as database code or file I/O, can simply run in synchronous Actors --- # Working Example https://github.com/utsl42/actix-test Demo using: - Actix - Actix-Web - MTBL - constant database C library - Slog - structured logging library - Tera - HTML templates - Serde - serialization/deserialization --- # actix-test Message Flow ![](actix_test_sequence.png)