eGo is a minimal library that helps build event-sourcing and CQRS applications through a simple interface, and it allows developers to describe their commands, events and states are defined using google protocol buffers. Under the hood, ego leverages Go-Akt to scale out and guarantee performant, reliable persistence.
- Installation
- Versioning
- Binaries and Go Versions
- Features
- Cluster
- Testkit
- Mocks
- Examples
- Contribution
go get github.com/tochemey/ego/v3
The version system adopted in eGo deviates a bit from the standard semantic versioning system. The version format is as follows:
- The
MAJOR
part of the version will stay atv3
for the meantime. - The
MINOR
part of the version will cater for any new features, breaking changes with a note on the breaking changes. - The
PATCH
part of the version will cater for dependency upgrades, bug fixes, security patches, and co.
The versioning will remain like v3.x.x
until further notice. The current version is v3.5.0
From | To | Minimum Go Version |
---|---|---|
v3.3.2 |
latest |
1.23.0 |
v2.0.2 |
v3.3.2 |
1.22.0 |
v1.1.3 |
v2.0.1 |
1.21.0 |
v1.0.0 |
v1.1.2 |
1.20.0 |
The EventSourcedBehavior
is central to maintaining data consistency, particularly in distributed systems.
It defines how to handle commands—requests to perform actions—which are always directed at the event-sourced entity.
In eGo, EventSourcedBehavior
instances are serializable, allowing them to be transported over the wire during relocation (e.g., in a clustered environment).
Commands sent to an EventSourcedBehavior
are processed sequentially.
When a command is handled, it may produce one or more events, which are then persisted in an event store.
Each persisted event is tagged with a revision number and a timestamp, enabling precise tracking and versioning.
The EventSourcedBehavior
is also responsible for defining how these events are applied to update the internal state of the entity.
The ultimate goal of event handling is to rebuild the current state from a history of past events.
When running in cluster mode, aggregate roots are automatically sharded for scalability and fault tolerance.
Command handlers define the business logic of the event-sourced actor. They are responsible for:
- Validating incoming commands against the current state.
- Deciding which events, if any, should be generated and persisted.
- Returning nil for no-op operations when no state changes are needed.
A command handler acts as the gatekeeper of your system’s business rules, ensuring that commands are only applied when valid. If validation succeeds, one or more events are returned, which express the state mutations. These events are then persisted and applied to produce a new, valid state.
Event handlers define how the state should be updated in response to events. These functions must be pure and deterministic, as they are used both when initially handling commands and when replaying the event log to reconstruct the entity’s state.
To define an event-sourced entity, one needs to:
- define the state of the event-sourced entity using google protocol buffers message
- define the various commands that will be handled by the event-sourced entity
- define the various events that are a result of the command handlers and that will be handled by the event sourced entity to return the new state of the event-sourced entity
- define and make sure the
events store
is properly implemented. - implement the
EventSourcedBehavior
interface. - call the
Entity
method of eGo engine
Every event handled by an event-sourced entity is pushed to an events stream. That enables real-time processing of events
without having to interact with the events store.
Just use Subscribe
method of Engine and start iterating through the messages and cast every message to
the Event.
One can add a projection to the eGo engine to help build a read model. Projections in eGo rely on an offset store to track how far they have consumed events persisted by the write-model. The offset used in eGo is a timestamp-based offset. One can also:
- remove a given projection: this will stop the projection and remove it from the system
- check the status of a given projection
One can implement a custom events store. See EventsStore. There are some pre-built events stores one can use out of the box. See Contrib
One can implement a custom offsets store. See OffsetStore. There are some pre-built offsets stores one can use out of the box. See Contrib
The DurableStateBehavior
represents a type of actor that persists its entire state after processing each command—unlike event-sourced actors, which persist only the events.
Like its event-sourced counterpart, DurableStateBehavior is serializable, meaning the actor can be moved across the network during relocation in distributed systems.
This actor maintains its current state in memory while handling commands. Based on the outcome of a command, it persists the full, updated state to a durable store (such as a SQL or NoSQL database). The behavior follows a simple and predictable model:
(State, Command) => State
Each command results in a new version of the actor’s state. Only the latest version is stored—there is no retained event history.
Therefore, DurableStateBehavior
is suitable for use cases where audit trails or state reconstruction are not required.
Although history is not tracked, each state version is tagged with a version number. This version must increment by one with every successful state transition. It is the responsibility of the command handler to ensure that the new state has a version exactly one greater than the previous
- Upon startup,
DurableStateBehavior
will attempt to recover the last known state from the durable store. - During a graceful shutdown, it persists the current state before stopping.
- This ensures consistency and resilience, even in clustered or distributed deployments.
DurableStateBehavior
is ideal for scenarios where simplicity, low-overhead persistence, and state durability are required—without the complexity of full event sourcing.
One can implement a custom state store. See Durable Store. There are some pre-built durable stores one can use out of the box. See Contrib
To define a durable state entity, one needs to:
- define the state of the entity using google protocol buffers message
- define the various commands that will be handled by the entity
- define and make sure the
durable state store
is properly implemented. - implements the
DurableStateBehavior
interface - start eGo engine with the option durable store using
WithStateStore
- call the
DurableStateEntity
method of eGo engine
Aspect | EventSourcedBehavior |
DurableStateBehavior |
---|---|---|
Persistence Model | Persists events that describe state changes | Persists the full state after each command |
State Reconstruction | Rebuilds state by replaying stored events | Loads the latest persisted state directly |
History Tracking | Full event history is retained | No event history, only latest state is kept |
Versioning | Revision number per event | Version number per full state snapshot |
Command Handlers | Produces one or more events from each command | Produces a new state directly from each command |
Event Handlers | Required to evolve state based on events | Not required (no events are emitted) |
Auditability | High – event log can be replayed for audit or debugging | Low – only the final state is available |
Complexity | Higher – requires modeling both events and state evolution | Lower – simpler, especially for CRUD-style operations |
Storage | Typically event stores (e.g., Kafka, EventStoreDB) | SQL, NoSQL, or any key-value store |
Use Cases | Financial ledgers, domain-driven designs, traceable workflows | Caches, configuration entities, simple aggregates |
Recovery | Via event replay | Via full state rehydration |
Serialization | Serializable and relocatable | Serializable and relocatable |
DurableStateBehavior
full state is pushed to an events stream.
That enables real-time processing of state without having to interact with the state store.
Just use Subscribe
method of Engine and start iterating through the messages and cast every message to
the DurableState.
eGo offers the following publisher APIs:
- EventPublisher - publishes
EventSourcedBehavior
events to any streaming platform - StatePublisher - publishes
DurableStateBehavior
state to any streaming platform
The following streaming connectors are implemented out of the box:
The cluster mode heavily relies on Go-Akt clustering. To enable clustering one need to use WithCluster
option
when creating the eGo engine.
eGo comes bundle with in-memory datastore that can be found in the testkit package. This can help play with eGo.
eGo ships in some mocks that can help mock the data stores for unit tests purpose.
Check the examples
kindly follow the instructions in the contribution doc