Specification
Note
This document defines the minimal feature set an Event Store must provide to be DCB compliant.
While we introduce certain concepts and terminology, implementations are not required to use the same terms — as long as they offer equivalent functionality.
An Event Store that supports DCB provides a way to:
- read Sequenced Events matching a Query, optionally starting from a specified Sequence Position
- append Event(s), optionally specifying an Append Condition to enforce consistency
Reading Events
The Event Store...
- ... MUST provide a way to filter Events based on their Event Type and/or Tag (see Query)
- ... SHOULD provide a way to read Events from a given starting Sequence Position
- ... MAY provide further filter options, e.g. for ordering or to limit the number of Events to load at once
A typical interface for reading events (pseudo-code):
Note: SequencedEvents
represents some form of iterable or reactive stream of Sequenced Events
Writing Events
The Event Store...
- ... MUST provide a way to atomically persist one or more Event(s)
- ... MUST fail if the Event Store contains at least one Event matching the Append Condition, if specified
A typical interface for writing events (pseudo-code):
Concepts
Query
The Query
describes constraints that must be matched by Events in the Event Store.
It effectively allows for filtering Events by their Type and/or Tags.
- It MUST contain a set of Query Items with at least one item or represent a query that matches all Events
- All Query Items are effectively combined with an OR, e.g. adding an extra Query Item will likely result in more Events being returned
To differentiate the two query variants, dedicated factory methods might be helpful:
Query Item
Each item of a Query allows to target Events by their Type and/or Tags.
An Event, to match a specific Query Item, needs to have the following characteristics:
- the Type MUST match one of the provided Types of the Query Item
- the Tags MUST contain all of the Tags specified by the Query Item
Example
The following example query would match Events that are either...
- ...of type
EventType1
OREventType2
- ...tagged
tag1
ANDtag2
- ...of type
EventType2
OREventType3
AND taggedtag1
ANDtag3
{
"items": [
{
"types": ["EventType1", "EventType2"]
},
{
"tags": ["tag1", "tag2"]
},
{
"types": ["EventType2", "EventType3"],
"tags": ["tag1", "tag3"]
}
]
}
Sequenced Event
Contains or embeds all information of the original Event
and its Sequence Position that was added during the append()
call.
- It MUST contain the Sequence Position
- It MUST contain the Event
- It MAY contain further fields, like metadata defined by the Event Store
Example
The following example shows a potential JSON representation of a Sequenced Event:
Sequence Position
When an Event is appended, the Event Store assigns a Sequence Position
to it.
It...
- MUST be unique in the Event Store
- MUST be monotonic increasing
- MAY contain gaps
Events
A set of Event instances that is passed to the append()
method of the Event Store
It...
- MUST not be empty
- MUST be iterable, each iteration returning an Event
Event
- It MUST contain an Event Type
- It MUST contain Event Data
- It MAY contain Tags
- It MAY contain further fields, like metadata defined by the client
Example
A potential JSON representation of an Event:
Event Type
Type of the event used to filter Events in the Query.
Event Data
Opaque payload of an Event
Tags
A set of Tags.
- It SHOULD not contain multiple Tags with the same value
Tag
A Tag
can add domain-specific metadata to an event, allowing for custom partitioning.
Usually, a Tag represents a concept of the domain, e.g. the type and id of an entity like product:p123
- It MAY represent a key/value pair such as
product:123
but that is irrelevant to the Event Store
Append Condition
The Append Condition is used to enforce consistency, ensuring that between the time of building the Decision Model and appending the events, no new events were stored by another client that match the same query.
- It MUST contain a
failIfEventsMatch
Query - this is typically the same Query that was used when building the Decision Model
- It MAY contain an
after
Sequence Position - this represents the highest position the client was aware of while building the Decision Model. The Event Store MUST ignore the Events before the specified position while checking the condition for appending events. Note: This number can be higher than the position of the last event matching the Query.
- if omitted, no Events will be ignored, effectively failing if any Event matches the specified Query