Consistency Guarantees¶
This guide explains the consistency guarantees provided by EventSourcingDB when writing, storing, and observing events. These guarantees help you reason about system behavior and build reliable, predictable workflows – even in concurrent or distributed environments.
Atomic Writes¶
When you write events to EventSourcingDB, they are stored as part of a single atomic transaction. This means:
- Either all events in the request are written together, or none are.
- If any part of the operation fails (e.g. a precondition is not met), no events are stored.
- This applies even when the events belong to different subjects.
You can safely write to multiple streams (subjects) in a single request, and EventSourcingDB guarantees that either all changes are committed or none. This enables consistent updates across aggregates without requiring distributed coordination.
Global Ordering¶
Every event in EventSourcingDB receives a unique, monotonically increasing numeric id. These IDs are assigned globally – across all subjects – and without gaps. The numeric id is not just a timestamp or sequence per stream – it is a strict global order across all events in the system.
This means you can rely on the order of events system-wide, not just within a single stream. The ordering is strict and consistent, regardless of where or how the events were written.
Visibility and Isolation¶
Events become visible only after the transaction has been successfully committed. While an event is being written, it is not yet readable – not through queries, not via observation.
Once committed, events are:
- Included in read responses
- Visible to EventQL queries
- Delivered to clients observing streams via the observe endpoint
This guarantees a clear boundary between committed and uncommitted data – and avoids race conditions caused by partially written state.
Concurrent Writes¶
EventSourcingDB safely handles concurrent write operations by internally serializing them. Even if multiple clients try to write at the same time, their requests are processed in a well-defined order.
You don't need to implement external locking or coordination – the database ensures that writes are processed consistently and without interference.
Preventing Duplicate Writes¶
If the same event is written multiple times, it will be stored again – unless you actively prevent it. EventSourcingDB does not automatically deduplicate write requests.
To avoid duplicates, use preconditions:
- Use
isSubjectPristineto ensure a subject is empty before initialization. - Use
isSubjectOnEventIdto ensure no new events have been added since the last read.
This gives you full control over how and when data is written – and helps you implement optimistic concurrency patterns.
Stream and Publish Behavior¶
After events are successfully stored, they are immediately published to any connected clients that are observing the affected subjects. This happens automatically and with minimal latency.
However, there is a small window between commit and delivery. In rare failure scenarios (e.g. a network interruption), a client might miss an event.
To handle this safely:
- Observing clients should always track the
idof the last event they received. - If a connection drops, reconnect using that ID as a starting point.
- For details, see Observing Events.
This pattern ensures that no events are lost – even if delivery is briefly interrupted.
A Note on External Consistency¶
EventSourcingDB does not support distributed transactions across external systems, such as databases or message brokers. If your workflow spans multiple systems, design for eventual consistency or use outbox patterns where appropriate.
Within the database itself, however, consistency is strong and clearly defined.
For additional details, refer to Eventual Consistency in Practice and Read-Model Consistency and Lag.
Building on a Solid Foundation¶
By providing strong consistency guarantees for atomicity, ordering, isolation, and publication, EventSourcingDB gives you a reliable foundation for building event-driven systems.
You can depend on these guarantees when designing projections, implementing workflows, and making decisions about system behavior under load or concurrency.