Actors + CQRS/DDD for the Fediverse

In this topic I will tell you a bit about the use case I am interested in, namely:

“Easing federated app development for the Fediverse”

W3C AtivityPub Recommendation is an actor-based protocol that allows federated communication based on a simple HTTP API where Actors (Person, Organization, Service, Application) exchange JSON-LD messages via inbox & outbox endpoints. This extensible protocol is the basis of the Fediverse where a large number of diverse apps interoperate and more than 5 million users interact.

It makes sense for a federated app to be actor-based internally as well, where server-to-server messages are handled by a Federation actor and delegated to e.g. Person actors referenced in the message. In my app design modularity and extensibility are key, and I intend to use domain-driven design ports & adapters architecture (similar to ftpgogo example project).

I won’t be using gRPC over the network (where I use AP), but was intending to use Hashicorp’s go-plugin (which uses gRPC) to have a dynamic plugin system and ability to add/remove module extensions dynamically at runtime. I still need to check if/how this can be combined with proto.actor (Proto.Remote?).

As for where DDD kicks in, I feel most for Alexey Zimarev’s approach to have actors in the application layer and keep the domain layer free of actor concerns (in contrast to Vaughn Vernon who talks about turning domain aggregates into actors).

Would be lovely if you could shine a light, give some feedback on this setup as it relates to proto.actor…


Update: I posted about this on the Fediverse here: https://mastodon.social/web/statuses/106396236289530868

Regarding architecture, this very much depends on the specific use case.
Our efforts are focused mostly on the Cluster support going forward.
Meaning you can have actors as a form of named entities, that live somewhere in your cluster.
These actors can then talk to individual aggregate roots in DDD.

This greatly simplifies all concerns around lifecycles, placement, and integrations.

If you need a plugin, this could simply be a new “Kind” of cluster actor and will be automatically
reachable via the cluster.

An intro to this topic can be found here:
https://proto.actor/docs/clusterintro/

Depending on how the data ingress, how data comes into the system.
There are options to optimize for locality also.
See Local Affinity
https://proto.actor/docs/local-affinity/

This works well if data has some form of affinity with nodes in the cluster.
e.g. using Apache Kafka, or even some form of sticky load-balancer for incoming HTTP

This is our go-to approach for scaling and ease of building systems.
Only in scenarios where this for some reason will not fit, we should fall back to plain actors and Proto.Remote.

Actors and Remote is the nuts and bolts of the architecture, while Cluster offers higher-level abstractions to build business features.

Feel free to reach out to me at roger@asynkron.se and we can take a deeper look at the specific scenario you have.

1 Like

The word “Cluster” as terminology sounds a bit ‘scary’, as it is usually not associated with simplicity in a solution, but rather ‘essential complexity’ given the project’s requirements.

For the project I have in mind it is more ‘universal applicability’ that is important, and initially most people will use the service platform for very basic use cases, so a KISS approach. It might even be used for single-user application, where someone self-hosts a Fediverse instance with various services that represent their online ‘social identity’. In that smallest-scale spectrum the DB may even be SQLite-in-production, and there’s no Kafka or k8s anywhere.

But there should be no problem if there are higher demands on its scalability, up-time and other NFR’s, and in theory the same setup (from the client’s perspective), now with a Postgres DB, might handle 500k active users. If that requires real clustering (e.g. having a Zookeeper in the mix) it would be great if that could be considered a ‘drop-in’ architecture components without having to think conceptually different on how the application works, i.e. the cluster is transparent just like remoting leads to location transparency.

So in that sense I am maybe not a typical proto.actor user in terms of scalability needs. I am also fairly new to Go, coming from Java where I’ve worked with Vert.x + Zookeeper before. So weighing best approaches and many concepts still new to me. I am seeking for a solution that is still easy to reason about and onboard contributors to, as it grows in size/complexity.

PS. The ActivityPub libraries I intend to build upon are called Go-Fed and specifically: GitHub - go-fed/activity: ActivityStreams & ActivityPub in golang, oh my!