{"id":20465734,"url":"https://github.com/tochemey/ego","last_synced_at":"2026-04-01T21:57:55.715Z","repository":{"id":153307101,"uuid":"628768209","full_name":"Tochemey/ego","owner":"Tochemey","description":"[Go]Minimal event sourcing/CQRS library using protocol buffers for commands, events and states.","archived":false,"fork":false,"pushed_at":"2025-03-14T10:16:34.000Z","size":682,"stargazers_count":42,"open_issues_count":1,"forks_count":6,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-03-27T00:22:41.368Z","etag":null,"topics":["cloud-computing","concurrent-programming","cqrs","cqrs-es","distributed-systems","event-driven","event-sourcing","go","golang","microservice","protocol-buffers","reactive-programming"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Tochemey.png","metadata":{"files":{"readme":"readme.md","changelog":null,"contributing":"contributing.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-04-16T23:58:44.000Z","updated_at":"2025-03-21T20:21:45.000Z","dependencies_parsed_at":"2023-09-27T15:22:49.249Z","dependency_job_id":"bdf10193-251d-4713-b4a8-6c8391f2b8fa","html_url":"https://github.com/Tochemey/ego","commit_stats":{"total_commits":114,"total_committers":3,"mean_commits":38.0,"dds":0.2192982456140351,"last_synced_commit":"9d13afbf9d65c996db607806d5d50450aaeba2de"},"previous_names":[],"tags_count":24,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Tochemey%2Fego","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Tochemey%2Fego/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Tochemey%2Fego/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Tochemey%2Fego/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Tochemey","download_url":"https://codeload.github.com/Tochemey/ego/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248687740,"owners_count":21145760,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cloud-computing","concurrent-programming","cqrs","cqrs-es","distributed-systems","event-driven","event-sourcing","go","golang","microservice","protocol-buffers","reactive-programming"],"created_at":"2024-11-15T13:19:35.671Z","updated_at":"2026-04-01T21:57:55.709Z","avatar_url":"https://github.com/Tochemey.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n  \u003cimg src=\"assets/logo.png\" alt=\"eGo Logo\" width=\"480\" /\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://github.com/Tochemey/ego/actions/workflows/build.yml\"\u003e\u003cimg src=\"https://img.shields.io/github/actions/workflow/status/Tochemey/ego/build.yml?branch=main\" alt=\"build\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://pkg.go.dev/github.com/tochemey/ego\"\u003e\u003cimg src=\"https://pkg.go.dev/badge/github.com/tochemey/ego.svg\" alt=\"Go Reference\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://go.dev/doc/install\"\u003e\u003cimg src=\"https://img.shields.io/github/go-mod/go-version/tochemey/ego\" alt=\"Go version\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://github.com/Tochemey/ego/releases\"\u003e\u003cimg src=\"https://img.shields.io/github/v/release/tochemey/ego?sort=semver\u0026display_name=release\" alt=\"GitHub Release\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://codecov.io/gh/Tochemey/ego\"\u003e\u003cimg src=\"https://codecov.io/gh/Tochemey/ego/branch/main/graph/badge.svg?token=Z5b9gM6Mnt\" alt=\"codecov\"\u003e\u003c/a\u003e\n\u003c/p\u003e\n\neGo is a minimal library for building event-sourced and durable-state CQRS applications in Go.\nIt lets you model your **commands**, **events**, and **state** with Protocol Buffers while relying on\n[Go-Akt](https://github.com/Tochemey/goakt) for actor-based execution, clustering, and scalable persistence.\n\nThe `main` branch currently targets the `v4` API surface. See the [changelog](./CHANGELOG.md) for the full release\nhistory and migration details.\n\n## Installation\n\n```bash\ngo get github.com/tochemey/ego/v4\n```\n\n## Why eGo\n\n- Protobuf-first modeling for commands, events, and state\n- Event-sourced and durable-state behaviors under one API\n- Built-in support for CQRS projections and event streaming\n- Snapshot-based recovery for faster replay\n- Event batching to amortize persistence cost across commands\n- Event adapters for schema evolution\n- OpenTelemetry-ready tracing and metrics\n- Encryption support for events and snapshots\n- Saga/process manager support for long-running workflows\n- Testkit and mocks for fast feedback\n\n## What's New in v4\n\nVersion `v4` introduces a major refresh across persistence, observability, operability, and developer experience.\n\n- **Snapshot Store**: persist snapshots independently from events with `SnapshotStore`, `WithSnapshotStore()`, and\n  `WithSnapshotInterval()`\n- **Event Batching**: amortize store round-trips by accumulating events across multiple commands and flushing them in a\n  single write with `WithBatchThreshold()` and `WithBatchFlushWindow()`\n- **Event Adapters**: evolve persisted event schemas during replay and projection consumption with the\n  `eventadapter` package\n- **OpenTelemetry Integration**: instrument command processing, persistence, projections, and active entities with\n  traces and metrics via `WithTelemetry()`\n- **Dead Letter Handler**: capture projection failures after retry exhaustion with `DeadLetterHandler`\n- **Projection Rebuild**: replay a projection from a chosen point in time using `Engine.RebuildProjection()`\n- **Scenario-based Testkit**: Given/When/Then APIs for event-sourced and durable-state behaviors\n- **Migration Utility**: migrate legacy inline state into snapshots with the `migration` package\n- **Projection Lag Monitoring**: inspect lag per shard with `Engine.ProjectionLag()` and dedicated metrics\n- **Retention Policies**: automatically clean up old events and snapshots after successful snapshot writes\n- **Encryption / GDPR Support**: encrypt payloads at rest and erase entity data with `Engine.EraseEntity()`\n- **Pluggable Logger**: use any logging backend through the `Logger` interface and `WithLogger()`\n- **Saga / Process Manager**: coordinate long-running workflows with compensation support\n\n## Core Building Blocks\n\n### Event-Sourced Behavior\n\n`EventSourcedBehavior` is eGo's core abstraction for domain models where state changes are represented as events.\nCommands are processed sequentially, resulting events are persisted, and state is rebuilt by replaying those events.\n\nIn `v4`, event-sourced entities also benefit from:\n\n- Snapshot-based recovery to reduce replay time\n- Event batching for higher throughput under sustained command load\n- Event adapters for schema evolution\n- Retention policies to control storage growth\n- Transparent encryption of events and snapshots\n\nTypical workflow:\n\n1. Define protobuf messages for state, commands, and events.\n2. Implement your `EventSourcedBehavior`.\n3. Provide an `EventsStore` and, ideally, a `SnapshotStore`.\n4. Configure runtime options such as snapshots, batching, retention, telemetry, or encryption.\n5. Start the entity with the eGo engine.\n\n#### Event Batching\n\nWhen an entity handles a high volume of commands, each individual store write becomes a throughput bottleneck.\nEvent batching addresses this by accumulating events from multiple commands and flushing them in a single write.\n\nEnable batching with two spawn options:\n\n```go\nengine.Entity(ctx, behavior,\n    ego.WithBatchThreshold(10),          // flush after 10 commands\n    ego.WithBatchFlushWindow(5*time.Millisecond), // or after 5ms, whichever comes first\n)\n```\n\nWhile a batch is being written, the actor stashes incoming commands and replays them once the write completes.\nCommands are processed optimistically against pending state, so callers do not observe any ordering anomalies.\n\nA threshold of `0` (the default) disables batching entirely, preserving the one-command-one-write behavior.\n\n### Durable-State Behavior\n\n`DurableStateBehavior` is a simpler model for cases where you only need the latest state instead of a full event log.\nEach successful command produces a new state version, and only the latest version is persisted.\n\nThis is a good fit for:\n\n- Configuration-style entities\n- Lower-overhead persistence needs\n- Use cases where audit replay is not required\n\nTypical workflow:\n\n1. Define protobuf messages for state and commands.\n2. Implement your `DurableStateBehavior`.\n3. Provide a durable state store with `WithStateStore()`.\n4. Start the entity with the engine.\n\n### Event-Sourced vs Durable-State\n\n| Aspect            | `EventSourcedBehavior`                    | `DurableStateBehavior`       |\n|-------------------|-------------------------------------------|------------------------------|\n| Persistence model | Persists domain events                    | Persists the latest state    |\n| Recovery          | Replays events, optionally from snapshots | Loads the latest state       |\n| History           | Full audit trail                          | No historical log            |\n| Complexity        | Higher                                    | Lower                        |\n| Best fit          | Traceable, business-critical workflows    | Simpler CRUD-like aggregates |\n\n## Projections \u0026 Publishers\n\neGo pushes persisted domain changes to a stream so read models and integrations can react without reading directly from\nthe primary store.\n\n### Projections\n\nProjections consume the write-model stream and build read models using an offset store.\nIn `v4`, projections gain several operator-friendly improvements:\n\n- Dead letter handling for unrecoverable projection failures\n- Rebuild support from a chosen timestamp\n- Lag, offset, and events-behind metrics per shard\n- Event adapter support during consumption\n- Automatic decryption before handlers process encrypted events\n\n### Publishers\n\neGo provides publisher APIs for both write models:\n\n- `EventPublisher` for `EventSourcedBehavior` events\n- `StatePublisher` for `DurableStateBehavior` state updates\n\nAvailable connectors:\n\n- Kafka\n- Pulsar\n- NATS\n- WebSocket\n\n## Observability\n\nObservability is a first-class concern in `v4`.\nWith `WithTelemetry()`, eGo can emit:\n\n- Trace spans for command processing\n- Command counters and latency histograms\n- Persisted-event counters\n- Projection processing counters\n- Active entity and projection counts\n- Projection lag, latest offset, and approximate events-behind metrics\n\n## Reliability \u0026 Operations\n\neGo includes several production-focused capabilities:\n\n- Faster recovery through snapshots\n- Storage cleanup through retention policies\n- At-rest encryption for events and snapshots\n- GDPR-style erasure with `Engine.EraseEntity()`\n- Pluggable structured logging\n\n## Sagas \u0026 Process Managers\n\n`v4` adds first-class saga support for long-running business processes that coordinate multiple entities.\n\nYou can:\n\n- Start a saga with `Engine.Saga()`\n- Inspect it with `Engine.SagaStatus()`\n- Model compensation logic for timeouts and failures\n- Persist saga state using the same event-sourced foundations\n\n## Clustering\n\neGo uses [Go-Akt](https://github.com/Tochemey/goakt#clustering) for clustering and entity distribution.\nIn `v4`, `WithCluster()` accepts `ego.ClusterProvider`, keeping your application code on eGo's abstraction instead of\ndepending directly on Go-Akt discovery types.\n\n## Testkit \u0026 Mocks\n\nThe [`testkit`](./testkit) package helps you validate behavior quickly with in-memory stores and scenario-based testing.\neGo also ships [`mocks`](./mocks) to simplify isolated unit tests around your stores and integrations.\n\n## Migration Notes\n\nUpgrading from `v3` to `v4` mainly involves:\n\n1. Updating imports from `github.com/tochemey/ego/v3` to `github.com/tochemey/ego/v4`\n2. Removing the `state *anypb.Any` parameter from projection handlers\n3. Migrating inline event state into snapshots with the migration utility\n4. Configuring a `SnapshotStore` for optimal event-sourced recovery\n5. Updating `WithLogger()` usage to the new `ego.Logger` interface\n6. Switching cluster integrations to `ego.ClusterProvider`\n\nSee [`CHANGELOG.md`](./CHANGELOG.md) for the full breaking-change list.\n\n## Examples\n\nBrowse the [examples](./example) directory for runnable samples and integration ideas.\n\n## Contributions\n\nPlease follow the [contribution guide](./contributing.md).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftochemey%2Fego","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftochemey%2Fego","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftochemey%2Fego/lists"}