| Crates.io | acty |
| lib.rs | acty |
| version | 1.0.1 |
| created_at | 2025-10-26 14:49:47.187293+00 |
| updated_at | 2025-11-15 07:51:53.496083+00 |
| description | A lightweight, async actor framework built on Tokio. |
| homepage | |
| repository | https://github.com/Numeration/acty |
| max_upload_size | |
| id | 1901491 |
| size | 93,910 |
English | 简体中文
Acty is a high-performance, extremely lightweight Actor framework built on top of Tokio. It aims to provide a simple, safe, and ergonomic concurrency model for the Rust asynchronous ecosystem.
Acty's design revolves around several core principles:
Actor trait needs to be implemented. No complex lifecycle hooks, no macro magic.Outbox). When all Outbox instances are dropped, the Actor automatically and gracefully shuts down. This eliminates the need for manual Actor termination management, fundamentally avoiding resource leaks.run method, rather than as struct fields. This makes state management clear and simple, and inherently prevents data races.mpsc channels and asynchronous Streams, allowing for easy composition with any library in the Tokio ecosystem (e.g., hyper, reqwest, tonic).Actor, ActorExt, AsyncClose)..start() (unbounded) or .start_with_mailbox_capacity(n) (bounded), with native back-pressure support.Launch trait allows for customizing the Actor's startup process (e.g., using different channel implementations or logging).Let's create a simple counter Actor.
1. Add Dependencies:
Add acty and tokio to your Cargo.toml.
[dependencies]
acty = "1"
tokio = { version = "1", features = ["full"] }
futures = "0.3"
2. Define the Actor:
An Actor is simply a struct that implements the acty::Actor trait.
use acty::{Actor, ActorExt, AsyncClose};
use futures::{Stream, StreamExt};
use std::pin::pin;
use tokio::sync::oneshot;
// The Actor struct is typically empty or contains only initial configuration.
struct Counter;
// The message types handled by the Actor.
enum CounterMessage {
Increment,
GetValue(oneshot::Sender<u64>),
}
// Implement the Actor trait to define its core logic.
impl Actor for Counter {
type Message = CounterMessage;
async fn run(self, inbox: impl Stream<Item = Self::Message> + Send) {
let mut inbox = pin!(inbox);
// The Actor's state is managed inside the run method.
let mut value = 0;
// Asynchronously process every incoming message.
while let Some(msg) = inbox.next().await {
match msg {
CounterMessage::Increment => value += 1,
CounterMessage::GetValue(responder) => {
// Send the result back via a oneshot channel.
let _ = responder.send(value);
}
}
}
}
}
3. Launch and Interact:
#[tokio::main]
async fn main() {
// Use .start() to launch the Actor and get an Outbox handle.
let counter = Counter.start();
// Sending messages is asynchronous, but is immediate for unbounded channels.
counter.send(CounterMessage::Increment).unwrap();
counter.send(CounterMessage::Increment).unwrap();
// Create a oneshot channel to retrieve the result.
let (tx, rx) = oneshot::channel();
counter.send(CounterMessage::GetValue(tx)).unwrap();
// Wait for the result.
let final_count = rx.await.expect("Actor did not respond");
println!("Final count: {}", final_count);
assert_eq!(final_count, 2);
// Close the Outbox. Since this is the last Outbox, the Actor will automatically shut down.
// .close().await waits for the Actor task to fully complete.
counter.close().await;
}
Want to explore more complex patterns? Check out the examples/ directory:
echo.rs: The simplest "Hello World" Actor.counter.rs: Demonstrates state management and the request-response pattern.manager_worker.rs: The classic manager-worker pattern, showing how an Actor can create and manage sub-Actors.simulated_io.rs: Demonstrates how an Actor can perform asynchronous I/O operations while processing messages.pub_sub.rs: The Publish-Subscribe pattern, demonstrating one-to-many message broadcasting.Contributions in any form are welcome! Whether it's submitting issues, creating Pull Requests, or improving documentation, we appreciate your help.
This project is distributed under either the MIT license or the Apache 2.0 license, at your option: