Hello Rustaceans,
I've been working on a new actor library called acto-rs.
This is in a very early phase (even if the version number is 0.5.0). The library is fairly un-documented, un-tested, full of unsafe code. May be the only part that I am comfortable with is the main API.
So this is about forming processing pipelines from components. The components can be connected by typed channels and they can have states. Nothing special so far. What is different from other similar solutions is:
- the components are categorised based on their connection topology to others. For example a
sink
component has only one input and it doesn't have outputs.
- the main goal of the library is low latency messaging between components. There are a few unusual measure there, like using bounded, non-blocking queues (lossyq) that has low overhead to the sender.
- the scheduler that runs the components, uses 1) fixed number of threads, 2) fixed scheduling rules to determine when to run a component. The components can be run on a periodic basis, or ASAP, or when a message arrives to it on one of its input channels, or when an external notification triggers it (for MIO integration).
I am looking for comments, ideas, feedback in general.
Thank you for your time if you look into it.
Best wishes, David
5 Likes
This is fantastic.
How does lossyq
's single producer/single consumer model work with some of the Actor primitives you've defined such as Scatter and Gather?
Any thoughts on including OTP-like supervision?
The Gather and Scatter trait both receive a vector of channels to work with. The actor implementation needs to implement the process function and it will need to iterate over the channels. If the scheduling rule for the actors is OnMessage then the scheduler makes sure to run the component when a message arrives to one of its channels.
The lossyq
read is done through an iterator which never blocks and is very cheap. Generally the actors should never wait on anything because the scheduler has no means to preempt them. External events like, wait for I/O can be integrated through the OnExternalEvent scheduling rule, which expects an outside mechanism to call notify on the scheduler.
acto-rs has no means for OTP like supervision at the moment. The minimum could be implemented easily is to add a rule to the scheduler for re-initializing an actor on error. I do see the value in the OTP supervision trees, only that it is a lot of work to implement.
This looks really cool, I was hoping someone would make some progress on an Actor library for Rust! I really like the look of Elixir's way of doing things, but something about that language just doesn't click with me, so to hear you're taking inspiration from there is cool.
Honestly, I'm rooting for this to succeed on the clever name alone
Thank you! So to be fair my actor library is light years behind Elixir's functionality. It was a starting point to look at and in multiple iterations I narrowed the feature set to something that I think it is usable alone.
acto-rs also does things differently. I chose to drop messages if the reader lags behind, rather than crashing. Its is built on strongly typed channels. The overhead of sending messages is lower (I have some numbers, but I decided to never publish any).
The strongly typed messages in particular capture my interest - the only other well known ish Actor library I've seen for Rust (RobotS) uses Box<Any>
as far as I can tell. Equally valid approach, but I prefer to avoid that kinda thing where possible!
I'll definitely have a play around with this at some point!