Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Experimenting with act-zero #5

Open
1 of 7 tasks
dmm opened this issue Nov 19, 2020 · 4 comments
Open
1 of 7 tasks

Experimenting with act-zero #5

dmm opened this issue Nov 19, 2020 · 4 comments

Comments

@dmm
Copy link

dmm commented Nov 19, 2020

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.

@dmm dmm changed the title Experimenting with act-zero examples Experimenting with act-zero Nov 19, 2020
@Diggsey
Copy link
Owner

Diggsey commented Nov 20, 2020

These all sound like great ideas! I'd definitely be open to accepting new examples, and if there's anything that you think would be reusable it might make sense to have an actix-web feature that enables additional functionality within act-zero itself.

My goal with this was to make async/await really easy, but I've only done the bare minimum to get to that point, so there's a ton of opportunities to improve it still.

Testing is something I have thought about a little. My current plan was to implement some kind of "snapshot" functionality that you could use to quickly get the state of all the actors in the system and make assertions about, but it's still very much in the ideas phase... There are also questions like: do we want to be able to make actors completely deterministic? That would certainly help with tests but might be quite difficult to accomplish.

@praveenperera
Copy link

  • 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.

This would be really cool. You could implement a supervision tree and have the supervisor restart actors that die:

async fn spawn_child(&mut self) {
    self.child = spawn_actor(...);
    let termination = self.child.termination();
    self.addr.send_fut_with(|addr| async move {
        termination.await;
        // The child stopped for some reason, re-spawn it again
        send!(addr.spawn_child());
    });
}

from: #4 (comment)

I wonder if it would be possible to create an DynamicSupervisor like in elixir: https://hexdocs.pm/elixir/DynamicSupervisor.html

@dmm
Copy link
Author

dmm commented Jan 26, 2022

I've been playing with implementing a trait to allow an actor to handle stream values. My work so far can be found here: https://github.com/dmm/act-zero-stream/blob/main/src/stream.rs

I added the new StreamHandler trait to the example from your README.

#[async_trait]
impl StreamHandler<String> for SimpleGreeter {
    async fn started2(&mut self) {
        println!("Stream has started!");
    }

    async fn handle(&mut self, item: String) {
        println!("Got stream item: {}", item);
        if let Ok(Produces::Value(greeting)) = self.greet(item).await {
            println!("{}", greeting);
        }
    }

    async fn finished(&mut self) {
        println!("Stream has stopped!");
    }
}

The idea is that an actor will own (in the general sense) a stream and handle stream output as actor messages.

A couple of questions that came up:

  1. Is there a way to disambiguate a trait method in the send! macro? For example here I had to rename my StreamHandler function to started2 so that it wouldn't conflict with the Actor::started function. https://github.com/dmm/act-zero-stream/blob/main/src/stream.rs#L72
  2. Does this design make sense to you?

@dmm
Copy link
Author

dmm commented Jan 28, 2022

I've added a websocket example: https://github.com/dmm/act-zero-stream/blob/main/websocket/src/websocket_actor.rs

Receiving data from the client works well but now I need to figure out how to share the stream so the actor can send data as well.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants