{"id":37126089,"url":"https://github.com/rilder-almeida/sagas","last_synced_at":"2026-01-14T14:34:31.639Z","repository":{"id":176524136,"uuid":"656935859","full_name":"rilder-almeida/sagas","owner":"rilder-almeida","description":"A framework to implement the saga pattern in Go","archived":false,"fork":false,"pushed_at":"2024-10-31T15:57:55.000Z","size":62,"stargazers_count":19,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2024-10-31T16:34:39.071Z","etag":null,"topics":["distributed-systems","observer-pattern","saga-pattern"],"latest_commit_sha":null,"homepage":"https://pkg.go.dev/github.com/rilder-almeida/sagas","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/rilder-almeida.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","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":"2023-06-22T00:45:42.000Z","updated_at":"2024-10-31T15:57:59.000Z","dependencies_parsed_at":null,"dependency_job_id":"35760bb1-8952-4a68-a953-8cbc8d8cb0b5","html_url":"https://github.com/rilder-almeida/sagas","commit_stats":null,"previous_names":["rilder-almeida/sagas"],"tags_count":12,"template":false,"template_full_name":null,"purl":"pkg:github/rilder-almeida/sagas","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rilder-almeida%2Fsagas","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rilder-almeida%2Fsagas/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rilder-almeida%2Fsagas/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rilder-almeida%2Fsagas/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/rilder-almeida","download_url":"https://codeload.github.com/rilder-almeida/sagas/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rilder-almeida%2Fsagas/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28423610,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-14T13:30:50.153Z","status":"ssl_error","status_checked_at":"2026-01-14T13:29:08.907Z","response_time":107,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"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":["distributed-systems","observer-pattern","saga-pattern"],"created_at":"2026-01-14T14:34:31.117Z","updated_at":"2026-01-14T14:34:31.624Z","avatar_url":"https://github.com/rilder-almeida.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# sagas\n\nThis package provides a framework composed by the following objects: Saga, Step and Action. Action abstracts a function that will be executed by a Step. The Step executes the Action and publishes a event for the Saga, using the Notifier. The Saga cares about the execution of the steps, it receives the events from the Notifier through the Observer. The Saga's observer holds the Execution Plan that will determine the next Step to be executed.\n\nThe following diagram shows the relationship between the objects:\n\n\tsaga starts -\u003e- run step -\u003e- execute action -\u003e- publish event -\u003e- notify saga -\u003e- saga observes -\u003e- execution plan -\u003e- next step...\n\n## Overview\n\nThe sagas package is a framework to implement the saga pattern in Go. It was inspired on the article \"SAGAS\" by Hector Garcia-Molina, Kenneth Salem, and Harold F. Korth, published by the ACM in 1987, and the article \"Implementing Sagas\" by Caitie McCaffrey, published by Microsoft in 2016.\n\nInitially, the saga pattern was proposed to solve the problem of long-lived and complex transactions in distributed systems. In most cases, LLTs must preserve the consistency in the data, atomicity of the transactions and have to be a fault-tolerant process. Besides that, TTLs use to access many objects that may cause a deadlock or locks in the database for a long time.\n\nIn a short definition, a saga breaks a long-lived transaction into a sequence of transactions that can be executed in a distributed environment. Each transaction process data and publishes a message or event to trigger the next transactionin in the saga. If a transaction fails then a compensation must be executed to undo the changes or in some cases to make a compensating change. In other words, compensation transactions can be a rollback or roll-forward transaction. The transactions and compensations together form a saga.\n\nFor more information about the saga pattern, please read the articles:\n - [SAGAS](https://www.cs.cornell.edu/andru/cs711/2002fa/reading/sagas.pdf) by Hector Garcia-Molina, Kenneth Salem, and Harold F. Korth (1987)\n - [Applying the Saga Pattern](https://www.youtube.com/watch?v=xDuwrtwYHu8) by Caitie McCaffrey (2015)\n - [Distributed Sagas](https://github.com/aphyr/dist-sagas/blob/master/sagas.pdf) by Caitie McCaffrey, Kyle Kingsbury and Neha Narula (2016)\n - [Distributed Sagas: A Protocol for Coordinating Microservices](https://www.youtube.com/watch?v=0UTOLRTwOX0) by Caitie McCaffrey (2017)\n - [Fault-Tolerance and Data Consistency Using Distributed Sagas](https://sookocheff.com/post/architecture/fault-tolerance-and-data-consistency-using-distributed-sagas/) by Kevin Sookocheff (2018)\n\n## Implementation\n\n```go\nfunc main() {\n\t// Given a number to divide\n\tdividend := flag.Int(\"number\", 0, \"an int to divide\")\n\tflag.Parse()\n\n\t// Create a Retrier to retry the action if it fails\n\tretrier := sagas.NewRetrier(sagas.BackoffConstant(3, 1*time.Second), nil)\n\n\t// Create a action function to verify if the number is divisible by 2\n\tactionFnVerify := func(number int) func(context.Context) error {\n\t\treturn func(ctx context.Context) error {\n\t\t\tif number%2 != 0 {\n\t\t\t\tlog.Println(\"number is not divisible by 2: \", number)\n\t\t\t\treturn errors.New(\"number is not divisible by 2\")\n\t\t\t}\n\t\t\tlog.Println(\"number is divisible by 2: \", number)\n\t\t\treturn nil\n\t\t}\n\t}\n\n\t// Create a step to verify if the number is divisible by 2\n\tstepVerify := sagas.NewStep(\"verify\", actionFnVerify(dividend), retrier)\n\n\t// Create a action function to divide the number by 2\n\tactionFnDivide := func(number int) func(context.Context) error {\n\t\treturn func(ctx context.Context) error {\n\t\t\tnumber = number / 2\n\t\t\tlog.Println(\"number divided by 2: \", number)\n\t\t\treturn nil\n\t\t}\n\t}\n\n\t// Create a action function to finish the saga\n\tactionFnFinish := func() func(context.Context) error {\n\t\treturn func(ctx context.Context) error {\n\t\t\tlog.Println(\"saga finished\")\n\t\t\treturn nil\n\t\t}\n\t}\n\n\t// Create a step to finish the saga\n\tstepFinish := sagas.NewStep(\"finish\", actionFnFinish(), nil)\n\n\t// Create a step to divide the number by 2\n\tstepDivide := sagas.NewStep(\"divide\", actionFnDivide(dividend), retrier)\n\n\t// Create a saga\n\tsaga := sagas.NewSaga()\n\n\t// Add the steps to the saga\n\tsaga.AddSteps(stepVerify, stepDivide, stepFinish)\n\n\t// Plan the execution of the steps\n\tsaga.When(stepVerify).Is(sagas.Failed).Then(sagas.NewAction(stepFinish.Run)).Plan()\n\tsaga.When(stepVerify).Is(sagas.Successed).Then(sagas.NewAction(stepDivide.Run)).Plan()\n\n\tsaga.When(stepDivide).Is(sagas.Completed).Then(sagas.NewAction(stepFinish.Run)).Plan()\n\n\t// Execute the saga\n\tsaga.Run(context.Background(), func() bool {\n\t\treturn stepFinish.GetState() == sagas.Completed\n\t})\n}\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frilder-almeida%2Fsagas","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frilder-almeida%2Fsagas","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frilder-almeida%2Fsagas/lists"}