News for hackers. Stuff that matters.

tqwewe

I haven't put any effort into any kind of snapshotting capabilities yet, since I won't want the scope to be too large and there's often ways of designing your system in ways where replaying isn't a big issue (the db scans are fast, designing aggregates to have a smaller scope/less overall events, etc).

But with increased resources, I can see some solutions being considered around snapshotting. For now the goal is heavily unix philosophy inspired: a really fast and purpose built event sourcing database

Yes exactly, I heard from an existing KurrentDB customer that the weird licensing change was actually a deal breaker causing them to move away from KurrentDB despite the migration pains.

I think a community, open source built project in Rust has been a missing piece I can hopefully help to solve.

This is resolved now :) Added better material around distributed actors.
I've added an indepth section to the kameo book about actor registration and lookup, including how it works: https://docs.page/tqwewe/kameo/distributed-actors/registerin...
I've added an indepth section to the kameo book about distributed actors if you'd like to read more. https://docs.page/tqwewe/kameo/distributed-actors
Great question, I did some digging into the source code of beam to help answer if signals should have special priority, and the conclusion (with the help of someone else from the elixir community) was that signals have no special priority over regular messages in beam. So I decided to take this same approach, where a regular message is just a `Signal::Message(M)` variant, and everything sent to the mailbox is a signal.

So gracefully shutting down an actor with `actor_ref.stop_gracefully().await` will process all pending messages before stopping. But the actor itself can be forcefully stopped with `actor_ref.kill()`

Thanks for the reply! The example you gave does make sense regarding the stage being used with the actors startup method.

I wasn't aware async_trait wasn't needed, thats nice to see.

Also congrats on it being used in such a big company, thats awesome! I have a lot of respect for ractor and appreciate your response

In the case of tokio, multiple actors can run on a single thread. Tokio uses a worker pool of threads equal to the number of cores on your system. So spawning a new actor will run amongs other actors. This lets us perform io operations in an actor, such as http connection, and progress other actors whilst waiting for a response.

Kameo does have a `spawn_in_thread` function for CPU bound actors if needed.

Under the hood it uses tokio runtime. So as long as you enable `rt-multi-thread` feature flag in tokio, and use `#[tokio::main]`, then yes! Actors can run on multiple threads. By default tokio uses worker threads, equal to the number of threads on your machine.

In kameo, all actors run in a `tokio::spawn` task.

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

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

Thank you for the lovely feedback! Happy to hear this. Will continue improving documentation, adding more examples to code docs, etc.
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
Yeah I definitely need to add some more documenation on this feature!
Thanks! Definitely agree with you, I'll create an issue for this
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.

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

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.

Show HN: Kameo – a Rust library for building fault-tolerant, async actors

https://github.com/tqwewe/kameo

Hi HN,I’m excited to share Kameo, a lightweight Rust library that helps you build fault-tolerant, distributed, and asynchronous actors. If you're working on distributed systems, microservices, or real-time applications, Kameo offers a simple yet powerful API for handling concurrency, panic recovery, and remote messaging between nodes.Key Features:- Async Rust: Each actor runs as a separate...

( Read More... | 58 comments | 38 points | on HN )