GithubHelp home page GithubHelp logo

act-zero's People

Contributors

deftsp avatar diggsey avatar mkj avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

act-zero's Issues

Using in a supervision tree style hierarchy

Hey here is how I'm exploring it right now, let me know what you think.

Main function creates the supervision tree root and starts its children:

#[tokio::main]
async fn main() -> Result<()> {
    color_eyre::install()?;
    env_logger::init();

    let cluster_manager = spawn_actor(ClusterManager::new().await);
    let _ = call!(cluster_manager.start_children()).await?;

    Ok(())
}

On root create, save self Addr and creates children and saves their addrs as well

#[async_trait]
impl Actor for ClusterManager {
    async fn started(&mut self, pid: Addr<Self>) -> ActorResult<()> {
        self.pid = pid.downgrade();

        self.app_manager_pid = spawn_actor(AppManager::new(self).await);
        self.build_manager_pid = spawn_actor(BuildManager::new(self).await);

        Produces::ok(())
    }
}

Root start children function

    async fn start_children(&mut self) -> ActorResult<Vec<()>> {
        use futures::stream::FuturesUnordered;
        use futures::StreamExt;

        let children = FuturesUnordered::new();
        children.push(call!(self.build_manager_pid.start_children()));
        children.push(call!(self.app_manager_pid.start_children()));

        // some weird nested async wrangling goes on here
        let ran: Vec<_> = children.collect().await;
        let filtered: Vec<()> = ran.into_iter().flatten().flatten().collect();

        Produces::ok(filtered)
    }

Child actor also has children of its own

    //BuildManager
    pub async fn start_children(&self) -> ActorResult<Vec<()>> {
        use futures::stream::FuturesUnordered;
        info!("Starting build manager");

        let bm_worker = spawn_actor(BuildMessageWorker::new(self).await);
        let incoming_worker = spawn_actor(IncomingMessageWorker::new(self).await);

        let children = FuturesUnordered::new();
        children.push(call!(bm_worker.listen()));
        children.push(call!(incoming_worker.listen()));

        let ran: Vec<ActorCallResult<()>> = children.collect().await;
        let filtered = ran.into_iter().filter_map(Result::ok).collect();

        Produces::ok(filtered)
    }

The ClusterManager BuildManager and AppManager actors need to stick around for ever always listening to (and handling) new messages coming from outside the system (through NATS).

Using in a supervision tree style hierarchy

Hey here is how I'm exploring it right now, let me know what you think.

Main function, supervision tree root:

#[tokio::main]
async fn main() -> Result<()> {
    color_eyre::install()?;
    env_logger::init();

    let cluster_manager_struct = ClusterManager::new().await;
    let cluster_manager = spawn_actor(cluster_manager_struct.clone());

    let _ = call!(cluster_manager.start_children()).await?;

    Ok(())
}

Starts children on startup

#[async_trait]
impl Actor for ClusterManager {
    async fn started(&mut self, pid: Addr<Self>) -> ActorResult<()> {
        self.pid = pid.downgrade();

        self.app_manager_pid = spawn_actor(AppManager::new(self).await);
        self.build_manager_pid = spawn_actor(BuildManager::new(self).await);

        Produces::ok(())
    }
}

Root start children function

    async fn start_children(&mut self) -> ActorResult<Vec<()>> {
        use futures::stream::FuturesUnordered;
        use futures::StreamExt;

        let children = FuturesUnordered::new();
        children.push(call!(self.build_manager_pid.start_children()));
        children.push(call!(self.app_manager_pid.start_children()));

        let ran: Vec<_> = children.collect().await;
        let filtered: Vec<()> = ran.into_iter().flatten().flatten().collect();

        Produces::ok(filtered)
    }

Child actor also has children of its own

    //BuildManager
    pub async fn start_children(&self) -> ActorResult<Vec<()>> {
        use futures::stream::FuturesUnordered;
        info!("Starting build manager");

        let bm_worker = spawn_actor(BuildMessageWorker::new(self).await);
        let incoming_worker = spawn_actor(IncomingMessageWorker::new(self).await);

        let children = FuturesUnordered::new();
        children.push(call!(bm_worker.listen()));
        children.push(call!(incoming_worker.listen()));

        let ran: Vec<ActorCallResult<()>> = children.collect().await;
        let filtered = ran.into_iter().filter_map(Result::ok).collect();

        Produces::ok(filtered)
    }

Waiting for drop to complete

Firstly many thanks for act-zero - it's very nice to work with. I've converted a program to it from Riker.

I'm trying to run some cleanup in my actor's drop(), but I can't figure a way to wait for it to complete. .termination()returns immediately. I guess the channel is closed before the inner actor is dropped?
I guess maybe the AddrInner could drop its Actor value before closing channels, but I'm not sure where. Any ideas would be appreciated.

// Copy of using_async_std example
use act_zero::runtimes::async_std::spawn_actor;
use act_zero::*;

struct HelloWorldActor;

impl Actor for HelloWorldActor {}

impl HelloWorldActor {
    async fn say_hello(&mut self) {
        println!("Hello, world!");
    }
}

impl Drop for HelloWorldActor {
    fn drop(&mut self) {
        println!("actor drop starts, waiting a sec");
        std::thread::sleep(std::time::Duration::from_secs(1));
        println!("actor drop done");
    }
}

#[async_std::main]
async fn main() -> Result<(), ActorError> {
    let addr = spawn_actor(HelloWorldActor);
    call!(addr.say_hello()).await?;
    let ended = addr.termination();
    std::mem::drop(addr);
    ended.await;
    println!("The End");
    Ok(())
% cargo run --example using_async_std --features=async-std
Hello, world!
actor drop starts, waiting a sec
The End
%

Upgrade to Tokio 1.0?

I attempted to do it but ran into problems that I don't currently have the skills to tackle: #8

Road Map for act-zero

I enjoyed playing with act-zero and will like to start working with it as a replacement for actix.
I will like to know the following:

  • Road Map for the act-zero
  • Benchmark comparison with the actix

I eagerly waiting for feedback on this, thanks

Use native async traits?

Hey since we can use async in traits since Rust 1.75, would it possible to now remove async_trait package?

I know it would be needed still to use dynamic dispatch. But i'm wondering if its possible to use it as a fallback?

Kill or stop Actor

Is there currently a way to kill or stop the actor?

Here is what I tried so far:

struct HelloWorldActor;

impl Actor for HelloWorldActor {}

impl HelloWorldActor {
    async fn say_hello(&mut self) {
        loop {
            println!("Hello, world!");
        }
    }
}

#[tokio::main]
async fn main() -> Result<()> {
    color_eyre::install()?;
    env_logger::init();

    let addr = spawn_actor(HelloWorldActor);
    send!(addr.say_hello());

    drop(addr);

    Ok(())
}

The document of "send!" is inaccurate

The current the document of send! said: "The method must take &mut self as the receiver."

I tried the method likes this async fn get_count(&self) -> ActorResult<usize>, it pass the compler.

Then I found the following words at https://old.reddit.com/r/rust/comments/hu10wh/actzero_asyncawait_compatible_actor_system/

Actor methods can have &self, &mut self or self: Addr<Local> receiver types, and this controls whether these methods can execute concurrently or not.

How about putting these words into the document of send!?

Working with Tokio Runtime

Hi, thanks for sharing such an amazing project.

I am interested in Actor and currently use actix. I am in search for a more flexible crate and I find act-zero amazing. I tried your tokio example but rust could not find tokio runtime.

   use act_zero::runtimes::tokio::spawn_actor;
   |                         ^^^^^ could not find `tokio` in `runtimes`

I am fairly new to rust, please help me out with possible solutions.
Thank you

Experimenting with act-zero

Hi Diggsey!

Thanks for sharing this interesting project. I like the async/await support and your emphasis on correctly mutating actor state.

I have a small application currently implemented in Actix that I'd like to explore reimplementing in act-zero. Rather than try to tackle the whole thing I thought I would make a few little programs in act-zero demonstrating how I commonly use actors. I'm not super experienced with async rust(or sync rust) so I thought I could get some feedback or maybe we could turn anything interesting into some act-zero examples?

  • actix-web integration
    The first example integrates actix-web and act-zero. In particular I wanted to send a message to an actor and create an http response from the actor's response. For the example I made an actor that tracks the number of times a route is hit. Another route returns the count.;

    This was pretty straightforward: https://github.com/dmm/act-zero-examples/blob/main/actix-web-interop/src/main.rs

    The only tricky part was using app_data() instead of data() to prevent the Addr<> from being wrapping in an Arc.

Some more things I'd like to attempt:

  • Processing an AsyncRead stream into actor messages
    My application launches several long running processes that communicate over stdout. I'd like to be able to process this as actor messages. I already use tokio_util::codec::length delimited to frame the stream so I think this will be straightforward.
  • actix-web websockets using act-zero
    actix-web's current websocket support uses Actix actors to process messages. I'd like to implement this using act-zero actors instead. It might make sense to make a crate for this if it works well. That in turn might be a good example of act-zero in a library.
  • dynamic actor launching and cleanup
    In several places I have an actor that will dynamically create and destroy actors. I have been doing this with a "Supervisor" actor that creates, and routes messages to, worker actors.
  • postgresql with diesel
    Right now I'm using an Actix SyncArbiter to make database calls through the synchronous diesel library. I think instead we'll use tokio::task::spawn_blocking.
  • Testing
    I've had a lot of trouble writing tests around Actix code. I want to play with testing in act-zero and see how it's better.
  • Other
    I'm sure there's other stuff.

Feel free to close this if you don't want it cluttering your issues.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.