Search code examples
microservicescqrsevent-sourcing

Implementing CQRS / ES the proper way


Recently I'm looking forward to implement the CQRS / ES pattern with Event sourcing in my microservices.

I've been reading for these patterns, but I have some questions that I couldn't find an answer anywhere:

  1. When doing CQRS / ES, should each microservice have its own local database anymore (Within microservice)?

    I know that there will be an event store for writes, and a read-only projection database and i totally understand their purpose, but do microservices need their own local database for any reason? (Advantages / disadvantages)

    Example: Order microservice could have local orders database, item service an items local database etc...apart from the Event source DB and projections database implemented.

  2. How to validate if some data exists in a microservice before actually issuing a command?

    Let's say i want to make a new order, so i assume first I have to check if that item is still in stock, then perform the other operation/s.

    However, if i want to check if an item is still in stock, where do i query that data, will it be the projection (read-only) database, or a local database that each microservice has?

I've read many articles about CQRS / ES at this point, but most of them just explain the concept rather than actually diving into real-life scenarios / explaining how to implement it. I would appreciate if you had any recommendations.

Much appreciated


Solution

  • In general, when dealing with microservices, it's recommended (regardless of whether or not you're doing CQRS/ES) that no two microservices use the same database, or at the very least that no two microservices be writing to the same database. This allows each microservice to control its schema, which only needs to change if the microservice needs it to. One other advantage of this is that the database becomes entirely encapsulated within the service: it's purely an implementation detail.

    It's entirely possible that a microservice implementing a read-model might not have a database: it might be able to keep all state in memory (an example might be a read-model which exposes metrics for your monitoring infrastructure), or it might simply be translating events from the write-model into commands to another service (so all of its state is just its position in the event stream).

    if i want to check if an item is still in stock, where do i query that data, will it be the projection (read-only) database, or a local database that each microservice has?

    In an event-sourced system, every view that's not the stream of events is a projection. So, depending on your requirements, your service can query another service or maintain its own view based on the events.

    Note that at any given instant there may exist an event which has been published to the event stream (i.e. it has indisputably happened) but for which there also exists a projection which has not processed the event: the projections are eventually consistent with the event stream. So any check of whether an item is in stock will only tell you that the item was in stock at some point in the past (never mind, to use Greg Young's example, that no in-stock data can guarantee that nothing's been stolen from the warehouse unless the thieves happened to have the decency to update the count as they walked out with their loot). The nanosecond after your query, it might receive word of an event which makes it out-of-stock before you placed your order.

    Accordingly, it may just be worth sending a command and letting it get reject your order if the item is not in stock. The write-side (which is the more strongly consistent part of the system, though it should be remembered that in many cases, one component's events are another component's commands) is under no obligation to accept every command; "command" in this context really means "polite request to publish events to the event stream which are conformant with my desired state of the universe".