Show HN: Kameo – Fault-tolerant async actors built on Tokio

80 pointsposted 10 hours ago
by tqwewe

32 Comments

chenzhekl

an hour ago

Curious, could it be used in wasm? I think it would be really cool if it can be used in browsers.

tqwewe

an hour ago

Would be absolutely awesome I agree! But, sadly I don't think tokio really runs in wasm just yet. But I see it being possible some day

binary132

2 hours ago

What I find myself wondering (maybe based on a superficial understanding) is how this is fundamentally different from, or better than grpc, and whether it could be used as an implementation of grpc.

tqwewe

2 hours ago

In my experience, setting up gRPC often involves a lot of boilerplate, particularly with code generation when using libraries like Tonic. While gRPC is great for well-defined, schema-driven communication, one of the big advantages of distributed actors in Kameo is that you can communicate with any actor on any node without the need to define a schema upfront.

With Kameo, an actor running on another node is simply accessed through a RemoteActorRef, and you can message it the same way you would interact with a local actor. This flexibility allows you to avoid the overhead of schema management while still achieving seamless communication across nodes, making the system more dynamic and less rigid compared to gRPC.

wildlogic

6 hours ago

Hi - any documentation regarding actor registration? Is there a conventional way to inform a remote actor about a new actor? Would this be sent in a message? How does the actor.register('name') work? Maybe could be a useful addition to the documentation. Thanks.

tqwewe

an hour ago

Hi, I'll probably need to add better documentation on the internals of how remote actors work. There's not really any special features for informing other actors when one is registered currently, but you could do this yourself of course via messaging.

actor.register('name') works by using a Kademlia DHT behind the scenes. This is implemented thanks to libp2p which handles all the complications of peer to peer connections

BWStearns

9 hours ago

Looks very cool. Is there any documentation on how it works for communication over a network? I see the remote/swarm section but is there an overview somewhere?

tqwewe

an hour ago

Thanks! Its definitely missing, I'll need to add that perhaps to the kameo book.

Its using libp2p under the hood with Kademlia distributed hash table for actor registrations.

throwawaymaths

9 hours ago

Is this actually distributed? I see no evidence that this can be used in conjunction with even ipc with builtin features.

hansonkd

9 hours ago

Check the examples folder.

qwertox

9 hours ago

https://github.com/tqwewe/kameo/blob/main/examples/remote.rs

    // Bootstrap the actor swarm
    if is_host {
        ActorSwarm::bootstrap()?
            .listen_on("/ip4/0.0.0.0/udp/8020/quic-v1".parse()?)
            .await?;
    } else {
        ActorSwarm::bootstrap()?.dial(
            DialOpts::unknown_peer_id()
                .address("/ip4/0.0.0.0/udp/8020/quic-v1".parse()?)
                .build(),
        );
    }


    let remote_actor_ref = RemoteActorRef::<MyActor>::lookup("my_actor").await?;
        match remote_actor_ref {
            Some(remote_actor_ref) => {
                let count = remote_actor_ref.ask(&Inc { amount: 10 }).send().await?;
                println!("Incremented! Count is {count}");
            }
            ...

throwawaymaths

7 hours ago

Thanks! It's not in the front page material.

tqwewe

an hour ago

Yeah I definitely need to add some more documenation on this feature!

fuddle

6 hours ago

Looks good, it would be great to see more examples in the docs.

tqwewe

an hour ago

Thanks! Definitely agree with you, I'll create an issue for this

__erik

10 hours ago

This looks really nice! Curious if its running in production anywhere

qwertox

9 hours ago

I agree, really nice syntax.

There's a limitation mentioned in the docs:

  While messages are processed sequentially within a single actor, Kameo allows for concurrent processing across multiple actors.
which is justified via

  This [sequential processing] model also ensures that messages are processed in the order they are received, which can be critical for maintaining consistency and correctness in certain applications.
I agree to this and it gives the library a well defined use.

Docs and examples are well made.

zackangelo

4 hours ago

This limitation is common to most implementations of the actor model. In fact, I think a lot of people would consider it a feature, not a limitation because it allows you to reason about your concurrent behavior in a more straightforward way.

tqwewe

an hour ago

Thank you for the lovely feedback! Happy to hear this. Will continue improving documentation, adding more examples to code docs, etc.

tqwewe

an hour ago

Not yet, however I hope to answer with yes soon. I'm using kameo heavily in a startup I'm building (oddselite.app). Hopefully will be released shortly for this to be a yes. But as of now, it's still quite a new library and the API has gone through many breaking changes to get where its at now

m00x

10 hours ago

What are the advantages and disadvantages vs using Actix or Ractor?

tqwewe

an hour ago

Actix was built initially using its own runtime and has gone over many iterations including a runtime change to tokio over its lifetime. In the past, building asynchronous actors with actix has been a huge pain and felt like a big after thought.

Ractor is nice, and I've used it in the past. A couple things differ between kameo and ractor:

- In ractor, messages must be defined in a single enum – in kameo, they can be separate structs each with their own `Message` implementation. This means messages can be implemented for multiple actors which can be quite useful.

- In ractor, the actor itself is not the state, meaning you must typically define two types per actor – in kameo, the actor itself is the state, which in my opinion simplifies things. As someone mentioned in a comment here, it was a bit of a turn off for me using ractor in the past and I didn't fully agree with this design decision

- Ractor requires the `#[async_trait]` macro – kameo does not.

There may be other obvious differences but I'm not super familiar with ractor besides these points

status_quo69

4 hours ago

I actually went through this exact exercise recently, but this library didn't show up in my searches for a good rust actor framework, so take that with a grain of salt. It looks very similar to the interface provided by actix at first blush, not sure how supervision works. My take is that most of these frameworks tend to solve with the same(ish) solution, so pick the one that has the best api. I liked ractor, although not having &mut self eventually wore me down. I swapped a small side project to use Stakker instead and while at first the macros intimidated me, the implementation really impressed me in terms of performance and API characteristics. It really feels like there's just enough there and no more.

stusmall

5 hours ago

The actix crate is deprecated. I looked on their site and repo and couldn't find an official announcement of deprecation but here is a link to what the lead said when I reached out with questions a few months ago: https://discord.com/channels/771444961383153695/771447523956...

EDIT: Tangent, but if anyone has experience making deterministic actor model systems that can be run under a property test I'd love to know more. It would make an amazing blog post even if it would have a very narrow audience

mtndew4brkfst

5 hours ago

PSA: Actix (not Actix-web) is fairly inactive - one of the maintainers informally said not to use it for any new projects during one of this year's RustConf chats.

TheMagicHorsey

10 hours ago

Looks really nice.

But sometimes when I see projects like this in other languages, I think, are you sure you don't want to use Erlang or something else on the BEAM runtime and just call Rust or C via their NIFs?

I used Erlang about a decade ago, and even then it was so robust, easy to use, and mature. Granted you have to offload anything performance-sensitive to native functions but the interface was straightforward.

In the Erlang community back then there were always legends about how Whatsapp had only 10 people and 40 servers to serve 1 Billion customers. Probably an exaggeration, but I could totally see it being true. That's how well thought out and robust it was.

Having said all that, I don't mean to diminish your accomplishment here. This is very cool!

hansonkd

9 hours ago

I think a lot of issues BEAM was trying to solve were solved by processors getting bigger and more cores.

BEAM's benefit 10-20 years ago where that inter-node communication was essentially the same as communicating in the same process. Meaning i could talk to an actor on a different machine the same way as if it was in the same process.

These days people just spin up more cores on one machine. Getting good performance out of multi-node erlang is a challenge and only really works if you can host all the servers on one rack to simulate a multi-core machine. The built in distributed part of erlang doesn't work so well in modern VPS / AWS setup, although some try.

binary132

2 hours ago

“Just spin up more cores on one machine” has a pretty low scale ceiling, don’t you think? What, 96 cores? Maybe a few more on ARM? What do you do when you need thousands or tens of thousands of cores?

Well, what I do is think of functions as services, and there are different ways to get that, but BEAM / OTP are surely among them.

tqwewe

an hour ago

It's a nice point. I am a fan of the beam runtime, and it has been an influence on the design decisions of kameo. However I don't see myself switching to another language from Rust anytime soon, especially with the amazing advancements with wasm and such.

Although Elixir is a nice language, I struggle to enjoy writing code in a language lacking types.

greenavocado

9 hours ago

Massive context switching and type checking on Erlang is inferior.