Disclaimer: This project is for educational purposes only and represents my own view on the DCB concept.
The simplest possible API and in-memory implementation of an Event Store. The API supports basics of DCB (Dynamic Consistency Boundary) concept.
If you are already familiar with DCB concepts, you might want to check out the sample right away. Otherwise, continue reading to get yourself familiar with the concepts.
Although simple, the Event Store API contains enough concepts to cover basic functionalities of an Event Store. It contains two operations:
- read - reads a finite stream of events from the Event Store based on provided criteria.
- append - appends events at the end of the Event Store log. It accepts the consistency condition as the parameter used to check the consistency of this append.
This Event Store is missing stream operation which would provide an indefinite stream of events based on certain criteria.
Before we explore the details of read and append let's explain the necessary terms in order to better understand mechanics of the Event Store.
term | definition |
---|---|
global sequence | Each event in the Event Store is associated with global sequence number which determines its position in the globally ordered Event Store log. The global sequence of the very first event is 0. |
head | global sequence of the very first event to be appended to the Event Store |
index | Specifies the event in more details. Event Store must store indices together with events and provide a search based on them. Usually, an Event Store index events based on indices for faster retrieval. |
criterion | Integral part of the criteria. It is composed of indices. Between them, an AND operator is applied - for an event to meet the criterion, all of the indices of the event must be matched with the criterion indices. |
criteria | Filters out events from the Event Store. It is composed of criterions. Between them, an OR operator is applied - for an event to meet the criteria, only one criterion should be satisfied. |
The best way to understand how criteria-based filtering works is to use an example. In this case we have a Student that can enroll a Course. There are events for student and course creation, renaming the course, course capacity change, and an event that student enrolled the course. The event stream is depicted in the image below.
All these events are indexed with specific Domain Identifiers. Certain events, like the fact that student subscribed to a course, are indexed with two indices - student and the course. The reason is that this event belongs to both, student and course domain concepts.
In order to handle student subscription command, we need to source our model based on the events we are interested in. In our case, those are events depicting whether the course capacity has changed and the fact that student has subscribed to a course. Let's see how to form a criteria for this use-case:
criteria(criterion(index("eventType", "CourseCapacityChanged"),
index("courseId", "jdsj4")),
criterion(index("eventType", "StudentSubscribedToCourse"),
index("courseId", "jdsj4")),
criterion(index("eventType", "StudentSubscribedToCourse"),
index("studentId", "gfh3j")))
Another interesting scenario would be to check whether the student subscribed to a course.
criteria(criterion(index("eventType", "StudentSubscribedToCourse"),
index("studentId", "gfh3j"),
index("courseId", "jdsj4")))
read operation provides marked events - all events matching the given criteria, starting from the given sequence. These events are marked with Event Store consistency marker at the time they are requested.
During the append each event is indexed with a set of indices associating this event with certain concepts from the Domain, or geospatial data, or technical aspects, or anything user-defined. It would be odd to see an index that does not already belong to the payload of the event. append accepts the event to be appended (obviously) and the consistency condition denoting consistency requirements for the append. consistency condition is composed of consistency marker and criteria.
consistency marker is telling the Event Store to start searching for events matching given criteria after its position. If there are no events matching the criteria after the consistency marker, consistency condition is fulfilled and the append is accepted, otherwise, it's not.
As a convenience the read operation returns events marked with the consistency marker of the Event Store. The command model uses read operation to source its state and make the decision based on the state. This decision is usually appending an event(s) to the Event Store. This exact command model is going to use the consistency marker from the read operation as the consistency marker for the append operation.