#reactive-programming #distributed-systems #framework #event-driven #agents #applications #actor-framework

acton-reactive

Acton Reactive is the main crate of the Acton framework, designed for building reactive, event-driven, and asynchronous systems. It provides intuitive abstractions to make working with distributed agents seamless and efficient.

5 releases

3.0.0-beta.3 Dec 2, 2024
1.2.4 Nov 30, 2024
1.1.1-beta.1 Oct 4, 2024
1.1.0-beta.1 Oct 3, 2024

#228 in Asynchronous

Download history 241/week @ 2024-09-29 42/week @ 2024-10-06 19/week @ 2024-10-13 1/week @ 2024-10-20 18/week @ 2024-11-03 10/week @ 2024-11-17 218/week @ 2024-11-24 867/week @ 2024-12-01

1,095 downloads per month

Apache-2.0 OR MIT

1MB
1.5K SLoC

Acton: A Friendly Reactive Framework for Rust

Welcome to Acton! This framework makes it easy to build fast, responsive Rust applications using a simple message-passing system. Think of Acton as a team of helpful workers (I call them "agents") who can pass messages to each other and handle different tasks independently. The name "Acton" comes from what these agents do - they "act on" the messages you send them!

What Makes Acton Special?

  • Easy-to-Use Agents: Agents are like independent workers in your application. Each one can handle its own tasks and keep track of its own information, making it natural to write programs that do many things at once.

  • Simple Message Passing: Agents communicate by sending messages to each other, just like people passing notes. Thanks to Rust's async/await features, these messages get delivered efficiently without blocking other work.

  • Flexible and Adaptable: You can easily customize Acton to fit your needs. Whether you're building a small application or a large system, Acton grows with you.

  • Safe and Reliable: Rust's type system helps ensure that messages get delivered to the right places. This means fewer bugs and more reliable applications.

  • Built-in Monitoring: Acton comes with tools to help you see what's happening inside your application, making it easier to find and fix problems.

Getting Started

Add Acton to your project by putting this in your Cargo.toml:

[dependencies]
acton-reactive = "3.0.0-beta.3"

How to Use Acton

Let's walk through a simple example to see how Acton works!

Step 1: Set Up Your Agent

First, let's import what I need and create a simple agent:

use acton_reactive::prelude::*;

// Create an agent that can keep track of a number
#[derive(Debug, Default)]
struct CounterAgent {
    count: usize,
}

Step 2: Define Your Messages

Messages are how agents communicate. Let's create some simple ones:

// The traditional way:
#[derive(Debug, Clone)]
struct PingMsg;

// Or use the helpful shortcut:
#[acton_message]
struct PongMsg;

#[acton_message]
struct GoodbyeMsg;

Step 3: Create Your Application

Here's how to set up your application and create an agent:

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    // Start up Acton
    let mut app = ActonApp::launch();

    // Create the counter agent
    let mut counter = app.new_agent::<CounterAgent>().await;

Step 4: Tell Your Agent How to Handle Messages

Now let's make the agent do something when it receives messages:

counter
    // When someone sends a Ping...
    .act_on::<PingMsg>(|agent, context| {
        println!("Got a ping! Adding to count...");
        agent.model.count += 1;

        // Send a Pong back
        let envelope = context.reply_envelope();
        Box::pin(async move {
            envelope.send(PongMsg).await;
        })
    })
    // When someone sends a Pong...
    .act_on::<PongMsg>(|agent, _envelope| {
        println!("Got a pong! Adding to count...");
        agent.model.count += 1;

        // Send a Goodbye to ourselves
        let handle = agent.handle().clone();
        AgentReply::from_async(async move {
            handle.send(GoodbyeMsg).await;
        })
    })
    // When someone says Goodbye...
    .act_on::<GoodbyeMsg>(|_agent, _envelope| {
        println!("Time to say goodbye!");
        AgentReply::immediate()
    });

Step 5: Start Your Agent and Send Messages

    // Start the agent
    let counter = counter.start().await;

    // Send it a message
    counter.send(PingMsg).await;

    // Shut everything down nicely
    app.shutdown_all().await?;
    Ok(())
}

Want to see more? Check out the example projects:

  • basic: A simple example like the one above

    Basic example of agents with message passing

  • lifecycles: See how agents start up and shut down Example of handing agent lifecycle events

  • broadcast: Learn how to send messages to multiple agents Example of broadcasting messages to multiple agents at once

  • fruit_market: A fun example showing how to build a more complex system Example of a more complex system with multiple agents handling different responsibilities )

Common Questions

Why do you call them "agents" instead of "actors"?

While Acton is similar to traditional actor frameworks (like Akka or Erlang), I use the term "agent" to keep things simple and friendly. An agent is just something that can receive messages and act on them - no complicated theory required!

What exactly is an agent?

An agent in Acton is like a helpful worker that can:

  • Keep track of its own information
  • Receive and respond to messages
  • Work independently of other agents
  • Handle tasks without blocking others

Think of agents as team members who can work on their own tasks while communicating with each other when needed.

Is Acton complicated to use?

Not at all! While Acton is powerful enough for complex applications, I've designed it to be easy to understand and use. It takes advantage of Rust's modern features (like async/await) to keep things simple while still being fast and reliable.

Want to Help?

I'd love your help making Acton even better! Feel free to:

  • Report issues you find
  • Suggest new features
  • Send pull requests
  • Share how you're using Acton

License

You can use Acton under either the MIT or Apache-2.0 license - whichever works better for you. Check out the LICENSE-MIT and LICENSE-APACHE files for the details.

Contact

Find me on Bluesky

Dependencies

~7–13MB
~148K SLoC