{"id":34126871,"url":"https://github.com/felixvo/event-sourcing-test-app","last_synced_at":"2025-12-14T23:51:31.676Z","repository":{"id":113713788,"uuid":"224577345","full_name":"felixvo/event-sourcing-test-app","owner":"felixvo","description":"sample event sourcing application using go and redis","archived":false,"fork":false,"pushed_at":"2022-06-15T14:29:22.000Z","size":2189,"stargazers_count":21,"open_issues_count":0,"forks_count":2,"subscribers_count":2,"default_branch":"master","last_synced_at":"2024-11-21T10:39:02.273Z","etag":null,"topics":["event-sourcing","go","redis"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/felixvo.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"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":"2019-11-28T05:36:23.000Z","updated_at":"2024-05-01T10:39:48.000Z","dependencies_parsed_at":"2023-04-30T21:15:44.000Z","dependency_job_id":null,"html_url":"https://github.com/felixvo/event-sourcing-test-app","commit_stats":null,"previous_names":["felixvo/lmax"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/felixvo/event-sourcing-test-app","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/felixvo%2Fevent-sourcing-test-app","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/felixvo%2Fevent-sourcing-test-app/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/felixvo%2Fevent-sourcing-test-app/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/felixvo%2Fevent-sourcing-test-app/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/felixvo","download_url":"https://codeload.github.com/felixvo/event-sourcing-test-app/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/felixvo%2Fevent-sourcing-test-app/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":27739526,"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","status":"online","status_checked_at":"2025-12-14T02:00:11.348Z","response_time":56,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":["event-sourcing","go","redis"],"created_at":"2025-12-14T23:51:27.766Z","updated_at":"2025-12-14T23:51:31.668Z","avatar_url":"https://github.com/felixvo.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Event Sourcing with Go and Redis\nNOTE: This code is not tested, just an experiment\n\nI thought you already heard about Event Sourcing in the past recent year.\nBut let's go through the definition again.\n\n\u003e Capture all changes to an application state as a sequence of events.\n\u003e Event Sourcing ensures that all changes to application state are stored as a sequence of events. - [Martin Fowler](https://martinfowler.com/eaaDev/EventSourcing.html)\n\nIf you know bitcoin/blockchain you will know it's quite similar with Event Sourcing.\n\n\u003e Your current balance (Application State) is calculated from a series of events in history (in the chain)\n![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/ztik9xqelulsh4lx3kl9.png)\n\nso you don't have a table like this in database\n\n|user_id|balance|\n|----|----|\n| 10 | 100$|\n| 7  | 200$|\n\nnow you have\n\n|events|\n|------|\n|user x top-up event|\n|user buy 5 items event|\n|user y top-up event|\n\nI've read many articles/blog posts about Event Sourcing so I try to make once.\n\n## What we will build?\nLet's say you have an e-commerce website and users can buy items from your website.\nSource: https://github.com/felixvo/lmax\n\nEntities:  \n- `User` will have `balance`.\n- `Item` will have `price` and number of `remain` items in the warehouse.\n\nEvents:  \n- `Topup`: increase user balance\n- `AddItem`: add more item to warehouse\n- `Order`: buy items\n\n## Directory Structure\n\n```\n├── cmd\n│   ├── consumer       # process events\n│   │   ├── handler    # handle new event base on event Type\n│   │   └── state\n│   └── producer       # publish events\n└── pkg\n    ├── event          # event definition\n    ├── snapshot       # snapshot state of the app\n    ├── user           # user domain\n    └── warehouse      # item domain\n```\n\n## Architecture\n![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/ui1bv7ili5wag324ucil.png)\n\n- Event storage: [Redis Stream](https://redis.io/topics/streams-intro)  \n\u003eEntry IDs\n\u003eThe entry ID returned by the XADD command, and identifying univocally \u003eeach entry inside a given stream, is composed of two parts:\n\u003e`\u003cmillisecondsTime\u003e-\u003csequenceNumber\u003e`\n\u003e I use this `Entry ID` to keep track of processed event\n\n- The consumer will consume events and build the application state\n- `snapshot` package will take the application state and save to redis every 30s. Application state will restore from this if our app crash\n\n## Run\n\n### Producer\n\nFirst, start the producer to insert some events to `redis stream`\n![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/v0scin2iq1cdcnu9nkaw.png)\n\n### Consumer\n\nNow start the consumer to consume events\n\n![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/eueho865f5couulhbnal.png)\nBecause the consumer consumes the events but not backup the state yet.\nIf you wait for more than 30s, you will see this message from console\n\n![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/0qkcmgzgwlhctk51q3bj.png)\n\nNow if you stop the app and start it again, the application state will restore from the latest snapshot, not reprocess the event again\n\n![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/vxxwbn2hfho3qj1hgi3b.png)\n\nThank you for reading!\nI hope the source code is clean enough for you to understand :scream:\n\n## Thoughts\n\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffelixvo%2Fevent-sourcing-test-app","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffelixvo%2Fevent-sourcing-test-app","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffelixvo%2Fevent-sourcing-test-app/lists"}