Swift Raft implementation

Very cool to see this work kicked off @makadaw!

A raft implementation for swift is very interesting to us. I'll watch the repo and perhaps can make some time to help out a bit. I worked on an implementation a few (many) years ago and made tons of small little mistakes in it along the way -- the protocol is seemingly "simple" but there's a ton of subtle things to get wrong in it :slight_smile: Happy to help getting it correct and efficient.


Suggestion: consider using actors right away.

I would really encourage expressing the protocol implementation in terms of actors (you can download a snapshot toolchain here Swift.org - Download Swift and enable them by passing -enable-experimental-concurrency. You can enable it for your package by following: Can "-Xfrontend -enable-experimental-concurrency" be enabled in a Package? - #3 by Diggory

Since you say this is a project to explore and exercise, let's not stick to pre-actors world as there's no necessity for doing so I assume? :slight_smile: On the other hand, modeling these protocols as actors is absolutely going to be the future IMHO.

I would suggest focusing on the core algorithm and building a large test suite confirming its correctness first, and we'll get it distributed soon enough :slight_smile: A strong test suite exercising the protocol as expressed as actors could be invaluable :star_struck: If you'd need any help how to get things set up let me know -- for now you'd need to use runAsyncAndBlock { ... } in the XCTests, but this will not be necessary eventually.


Thanks a lot for not pulling in Foundation here! That's a great decision for a library such as this.

API wise I think there's two options, either https://apple.github.io/swift-nio/docs/current/NIO/Structs/NonBlockingFileIO.html but it's API is a bit limited (on purpose kind of I guess), so perhaps you can get away with it. Otherwise I agree that the "right" API to use here is Swift System, althoughit is multi-platform not cross-platform so we're likely to need some small shim over it to issue "append to log" commands etc. But this should be easy enough to build as the number of operations you'd need for the log are not too crazy.

Eventually I'd hope Swift System or some other "async" APIs for IO to be provided by Swift to fit into the new async/await world, but we're not there yet. So all those calls will be blocking, so you'll need to put those "somewhere" in order not to block the event loop. For that purpose you could use a dedicated "IO" thread pool, by creating an instance of: https://apple.github.io/swift-nio/docs/current/NIO/Classes/NIOThreadPool.html and using it everywhere you'd need to perform this IO work.

Even with Actors this is true, so actors would be doing all the raft protocol work on their dispatchers, and for the log interactions we'd do the operations on the NIOThreadPool.

There are good ways to integrate EventLoopFuture with async/await so you can await elf on it -- let me know if you get to that point and happy to help, but it boils down to copy pasting this snippet: https://github.com/apple/swift-nio/pull/1701

NIO of course is an excellent choice for the networking, but we should try to keep distributed protocol implementations somewhat independent of NIO. You could have a look how we built such distributed protocol implementations in GitHub - apple/swift-cluster-membership: Distributed Membership Protocol implementations in Swift

There we implemented SWIM in a way that does not expose the fact it uses NIO in the "core protocol" implementation. That amount of separation may be too annoying here, but I think it would already be fantastic if we modelled peers as Actors with async functions on them, and implement the messaging they do there with NIO as a start. (so a peer would take some "transport" object that has NIO inside and send messages through that etc).


Overall, this is very exciting and I'd love to help out in some way so you can be successful with this implementation! :slight_smile:

4 Likes