3
votes

I have some questions above event-sourcing and cqrs in microservices architecture. I understand that after send command some microservice executes it and emits event. Event-store subcsribes on it and saves inside his database. Also some ReadModel basing on this event generates and saves optimized data inside read database.

My first question is - Can microservice has his own database and store data inside it too? Or maybe in event-sourcing approach microservices don't have their own databases and everything is only stored inside event store?

My second question is - when I execute command in microservice and need some data for validation purposes do I need call ReadModel or what? Assuming microservices haven't got their own databases I have no choice?

1

1 Answers

3
votes

Can microservice has his own database and store data inside it too?

Definitely, microservice can have its own database. But let's use terms from ES/CQRS. Database can represent Event Store (append-only log of immutabale events) and Read Model - some database used to answer queries which is populated by proseccing events.

So, microservice can have its own Read model, populated from events from other microservices.

Or microservice can process commands and save events to the shared Event Store.

Or microservice can process commands and save events to its own Event store.

Choice is yours, and it depends on degree of separation you want to achieve among microservices.

I would put all events that usually consumed together into same Event store. Which means I should be able to query for these events and have a single ordered stream as a result.

when I execute command in microservice and need some data for validation purposes do I need call ReadModel or what?

Command is executed by Aggregate, that has its own state. This state is built by processing all events for this aggregate, and this state should be used to validate a command.

You cannot/should not talk to Read Models in the command handler, primarily because those read models are not consistent with aggregate state. Aggregate state is consistent.

You can query Read Model before sending a command (to make sure it can be sent). But in command handler you need to rely on aggregate state only.

There is a famous case of registering user with requirement of a unique name. As a primary validation, in your UI code you can query read model and tell user that entered name is taken. If name is not taken, UI lets user issue a command. I'm assuming your Aggregate root is user.

But when processing this command ({id:123, type:CREATE_USER, name:somename}) you cannot check that "somename" is taken, because aggregate state for user 123 does not contain a list of taken names. You can potentially query some AllUsernames read model, but it can be milliseconds old, and some other user could take this "somename" already. So in this scenario, you will find a duplication during adding names to read model. And at that point you can do some compensation action - usually issue a command to suspend a user with duplicated name and ask him to re-register or change his name somehow.

It may seems strange, but if you have a really distributed system with several replicas of user list, you'll have the same problem, so why not just embrace the fact that data is always not fully consistent, and just deal with it?