I just discovered the dapr project and I was curious what other folks think about this level of abstraction. Haven’t spent much time with the project yet but so far it seems to offer a way to write distributed actors in any language that interfaces with REST or gRPC. I am guessing that it should be possible to create a dapr swift sdk that exposes distributed actors in plain swift but be powered by dapr for setting up the transport and perhaps some long living state for actors that die.
Here is a little more information about creating a language specific sdk. In summary most of the API for a new language SDK is autogenerated but the Actor sdk part needs to be manual to take into account usability concerns for the target language.
Good question, let's see...
Let me preface this with a bunch of caveats: Dapr has been around for a while but I've never really dug deep into it. I think there's actually a lot of platforms we can either integrate with or make use of and make them have a "Swift native" distributed actor user experience. There's also Kalix ("Akka serverless") which is another runtime like this.
Can we do "virtual actors" with Swift's distributed actors?
Our distributed actor design is very much so prepared to handle the virtual actor pattern; we "just" need the runtime impls to catch up a bit with the language
For example, you'll notice (quote from the docs you linked):
Each such actor is uniquely identified by an actor ID.
That's why distributed actors have the
Self.ID which is managed by the actor system This is a common trait for all distributed actor runtimes, from Akka, Orleans and all the way to OTP and Dapr and others.
In general, you should probably start with:
as it explains the concept pretty well. And please note that the pattern originally comes from Orleans, so more docs for inspiration are available here:
I'd also give Kalix a look, since Akka's "cluster sharding + persistence" is exactly the same as the virtual actors pattern in practice, and Kalix is the serverless offering.
I think it might be much easier to get a Swift SDK going for Kalix and we'd then be able to write both servers and clients using DA... (supported languages Supported Languages :: Kalix Documentation )
Sidenote: Pure Swift
We could also implement a pure-swift solution for virtual actors based on the cluster library: GitHub - apple/swift-distributed-actors: Peer-to-peer cluster implementation for Swift Distributed Actors
I'm in the middle of updating it to the latest toolchains as we're preparing for WWDC, so within a few weeks one could start playing around with implementing Virtual Actors for the cluster. It'd mean you can "host" virtual actors with a very minimal deployment. Though of course the above mentioned managed runtimes are also interesting.
We could also look at extending the Swift AWS Lambda runtime:
to be able to "host" virtual distributed actors...
So yeah, lots of work ahead of us and we'll need to figure out as a community which runtime is most interesting and try out a few as OSS libs I think
What about Dapr right now then?
I'll be honest here that it is unlikely that I myself will have the time to look into integrating with Dapr, but I do agree that such integrations is exactly what we should be doing with DA as it gets released with Swift 5.7
If you'd like to look into it I'm more than happy to offer consultations or something like that to help you write such Swift SDK for it
I am thinking about spending time on this space since if this is successful maybe i can start using swift on the back end at work (a yak shaving exercise)
At first look I see three areas: Transport, Distributed Internal state, Reentrancy.
Do you see any other main areas between virtual actors and distributed actors in Swift?
swift distributed actors reentrancy is the default ( and only choice I think) vs most virtual actor frameworks making it configurable. So a client library that adapts swift DA to a virtual actor framework should default to DA design choices first.
Reentrancy is not really something for you to work on here all that much. Rather, it is a function of how messages are delivered. As the runtime (SDK) implementation you can simply "wait to deliver the next message until the previous has been completed" and from the runtime's perspective you're not the cause of any reentrancy to the actor; if the (swift) actor happens to undergo reentrancy that's up to it and this is not something you're able to influence at all unless you are the Swift runtime -- so I suggest ignoring this topic at least for the first steps here.
What you have to actually implement I assume though is a minimal "SDK" that would bridge a declared
distributed actor type into whatever Dapr expects types to call into.
This really isn't all that much different to what runtimes such as the cluster GitHub - apple/swift-distributed-actors: Peer-to-peer cluster implementation for Swift Distributed Actors need to do:
- resolve actors for incoming IDs (keep some mapping in memory from ID to instances)
- deliver messages to them (invoke
- deliver replies to callers
The usual caveat applies though that I’m no Dapper expert, so that part would best to ask it’s devs
If you get started here feel free to let me know and we can look into what approach makes sense and I'm more than happy to provide hints and guidance! Looking forward to this!y