186 karma · joined February 16, 2023
The crate that helped this is erl_dist. I'd love to open source the code at some point, but it's not quite there yet
It's come a long way since it started and I'm thrilled I can talk about it publicly now and it's usage at Meta (some at least lol).
Question for you, I was poking around in the codebase and how do you handle your Signal priorities? Like if a link died, and there's 1000 messages in the queue already, or if it's a bounded mailbox, would the link died (or even stop) messages be delayed by that much?
Have you looked into prioritization of those messages such that it's not globally FIFO?
Here's the RustConf presentation for anyone interested https://slawlor.github.io/ractor/assets/rustconf2024_present...
Imagine opening a socket, if you have a mutable self the caller who is going to spawn that actor needs to open the socket themselves and risk the failure there. Instead of the actor who would eventually be responsible for said socket. This is outlined in our docs the motivation for this. Essentially the actor is responsible for creation of their state and any risks associated with that.
- for the async trait point we actually do support the native async traits without the boxing magic macro. It's a feature you can disable if you so wish but it impacts factories since you can't then box traits with native future returns https://github.com/slawlor/ractor/pull/202
(For transparency I'm the author of ractor)
While we do maintain the directory, we are held to an honest standard by our audit logs. Should any auditor find invalid records, they can publicly hold us accountable.
At least Rust doesn't have a garbage collector, so when the actor is stopped + dropped, it'll cleanup not only it's state but also it's message queue's flushing them so that all memory is released at the time of drop.
As far as deployment, do you mean like how we came to build this? Or like how you'd actually deploy it...? Because that's really up to the program being built imo
1. If you would want independent message handlers, normally we'd just add functions off the state which would be called strait from the message handler's match statement. I.e. something like self.handle_msg_1(message, state, ...). We looked at having multiple handlers but you kind of either get into generic's hell or having to do some kind of ugly proc macro. We figured this left it up to the implementor on how you want to handle it
2. Sequential processing would really be a factory. That would do parallel work of jobs using a basic actor implementation while handling concurrent work limits, job routing, etc. Otherwise you could always spawn inside your actor and like a wait on multiple handles if you wanted, but that gets messy and kind of diverges from the true intent. There is a factory implementation in the base ractor lib, feel free to take a look!
So it's a tradeoff on stuff like syntactic sugar and speed imo