Repository Interfaces and Guarantees
Repository Interface and Guarantees describes interfaces and guarantees a repository provides. As a part of this description, it describes the overall composition and flow of data in a repository.
Copyright (c) 2016 The Editor and Contributors
This Specification is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version.
This Specification is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with this program; if not, see http://www.gnu.org/licenses.
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119.
- To scope repository functionality
- To present the flow of data inside a repository
- To establish explicit guarantees a repository provides
- To provide a guideline for independent repository implementations
A repository MUST have a single hybrid logical clock timestamp (TR) associated with it. It indicates the upper temporal boundary of the all applied write operations performed on the repository.
When repository is started for the first time, TR MUST be initialized with current physical time.
A repository MUST monotonously increase TR, which MUST be equal or greater than the timestamp of the latest write operation. A repository MUST NOT modify TR unless an operation has succeeded.
At any time, when TR is updated, it MUST be serialized to a durable storage. Upon a subsequent restart, TR MUST be initialized from that durable storage.
Locking provider (LP) is a simple interface intended to provide a mutex primitive. Superficially, it can be expressed as a function Lock(Identifier) returning an Unlock() closure.
This functionality enables applications to establish write constraints and ensure the consistency of the event domain model.
A repository MUST provide at least one LP implementation and MAY choose an appropriately fitting implementation when an LP is requested or required.
For the purpose of this specification, we define command C as a composition of:
- an RFC1/ELF command entity T
- a function E(C, Repository, LP) that returns a stream of events EK
- a function R(C) that returns an arbitrary value (a result function)
Publishing is a publicly interfaced write operation handled by a repository.
It MUST have an input command C and MUST synchronously and/or asynchronously return the value of R(C) upon completion.
4.1. Command Transactional Boundaries
Command processing MUST NOT make any changes visible to other users of the repository until command C is committed, forming a transaction TxC.
4.2. Command Timestamp
If an input command C doesn't have a timestamp, TR' = TR is updated with current time and is also assigned as a timestamp of the command (TC). Otherwise, TR' = TR is updated with TC to ensure updated TR' is greater than TC.
Repository MUST NOT assign TR' value to TR at this time.
4.3. Event Collection
For every event Ek, repository MUST perform the following operations:
- If Ek does not have a timestamp, TR' is updated with current time and is also assigned as a timestamp of the event (TE). Otherwise TR' is updated with TE to ensure updated TR' is greater than TE..
- Record Ek and associate it with command C.
- Index Ek (see 5. Indexing and Querying).
- Check if there any parties interested in this event should TxC successfuly commit (entity subscribers). If there are any, Ek should be associated with these matching entity subscribers.
- Record a corresponding
EventCausalityEstablishedevent establishing a causal relationship between command C and event E
Repository MAY record EntityLayoutIntroduced when it first encounters a new layout.
- Layout name:
The relationship between
CommandTerminatedExceptionally and the command
is established through a matching
Repository MAY add arbitrary additional informational events referring to the instance of this
CommandTerminatedExceptionally event to capture details of the failure. For human-readable descriptions, it is RECOMMENDED to use rfc.eventsourcing.com/spec:3/CEP/#DescriptionChanged.
4.4. Command Colleciton
Repository MUST perform the following operations:
- Record command C.
- Index command C (see 5. Indexing and Querying).
- Check if there any parties interested in this command should TxC successfuly commit (entity subscribers). If there are any, C should be associated with these matching entity subscribers.
All changes made within TxC MUST be made available to all other users of the repository.
TR MUST be assigned to TR' (last event's timestamp or command's timestamp if it produced an empty stream EK).
All recorded matches between entity subscribers and entity recorded within TxC, entity subscribers MUST receive matched entities according to their expectations.
Repository MUST provide an interface for querying indexed entities. No universal standard is defined at the moment and independent implementations SHOULD seek to provide their own indexing and querying mechanisms.
Should such a standard emerge, implementations MUST adhere to it once it reaches Stable level of maturity.