Hi, I’m trying to build an application using Microsoft Orleans and EventStoreDb.
In the document for grpc client, I don’t see any place saying that we have a connection pool build into the client itself, so I assume I have to close the connection after I use it.
I also search the source code of the grpc client for ‘pool’ and can’t find anything.
If that was true, then the recommended approach would be open and close the connection right after I’m done using it?
If so, should we update the document to make it clear?
We don’t have pooling ; it’s http/2 under the hood.
Ususally there is 1 connection per process and there is no need to close it.
In the case of an actor model you could have 1 actor holding the connection and responding to read / append requests from other actors ( assuming you have an actor instance per entity and read model in your system)
We know about Orleans-based systems where each actor reads and appends events using an injected EventStoreClient singleton. I would still recommend doing it similarly to what Yves wrote, but maybe not with one, but several stateless worker grains that would serve read calls. Appends are fine (I think) but the main issue happens when a silo starts up and starts to spawn a lot of grains at the same, triggering lots of concurrent reads. It can lead to the database being overloaded with read requests. The database doesn’t have any connection limits, so it will be like self-inflicted DDoS attack.
That is great suggestions, I have never thought about that before.
The thing is after weeks trying to get things to work with confident, I decided to use a library instead, and Eventuous is the one I choose.
My strategy is to use AggregateStore inside a grain to load the aggregate. The grain now is just a container for synchronize commands/events to the aggregate.
The reason I need actor model is it help eliminate the need to reason about optimistic concurrency exception.
Now the new concern of self DDOS make the strategy go bankrupt.
But luckily I found this github issue from 2018:
Which have Orleans developer confirm that Orleans will not migrate existing grain when a new node join the cluster. Auto migration only happen on Akka at that time.
And in 2022, Orleans implement auto grain migration, which migrate grains automatically to rebalance the cluster:
And again, luckily it preserve soft state:
Soft-state preservation during upgrades
Some customers have told us that they would like to preserve running grain state during migrations.
This state tends to be soft state, state which can be reconstructed (perhaps loaded from a database) at a cost.
If a live grain migration mechanism includes a facility to preserve soft state across a migration, then that could be utilized by these customers to preserve soft state.
Additionally, it can be utilized by grain state providers to avoid needing to reload state from the database during the migration, lessening database load.
Which mean the aggregate that I already load into memory still there after the migration.
So, what i need to do is to check for the in-memory aggregate inside the OnActivateAsync method of the grain, if the aggregate is there then I don’t need to reload it.
Personally I feel like actor model and event sourcing is born for the other, it is a beautiful combination.
It would be nice if Eventuous have an extension to support this architecture (I would if I have a bit more experience on Orleans, maybe 6 months from now).
Eventuous has a cached state feature planned, and when combined with session affinity, it solves some of the problems that Actor Model promises to solve. Of course, Actor Model shines on higher load, like you said, you would never get optimistic concurrency exceptions, and all the processing will become linear.
About your impression that Actor Model and Event Sourcing play nicely together - I agree, I have the same impression, and I participated in implementing several actor-based systems using Porto.Actor and EventStoreDB. By the way, Porto.Actor persistence is event-sourced from the start, so it was quite easy to use. Unlike the Event Sourcing idea in Orleans, which is done quite badly. It was quite shocking when I found out how it works in Orleans as they persist the whole event stream as one object, and instead of granular appends you quite fast get a gargantuan blob being pushed to persistence.
Btw, I am keen to include support for Actor Model frameworks such as Orleans and Porto.Actor to Eventuous, so I am open for contributions. It’s actually quite easy to implement, I think. I like your thought that the actor is not an aggregate, I see it way too often. It’s indeed much closer to the command service concept, taking care of persistence and calling aggregate functions.