{"id":16372237,"url":"https://github.com/meadsteve/talepy","last_synced_at":"2025-03-21T01:31:40.326Z","repository":{"id":57473257,"uuid":"138919854","full_name":"meadsteve/talepy","owner":"meadsteve","description":"📚Coordinate \"transactions\" across a number of services in python","archived":false,"fork":false,"pushed_at":"2024-03-20T15:45:09.000Z","size":105,"stargazers_count":22,"open_issues_count":6,"forks_count":2,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-03-15T01:36:11.385Z","etag":null,"topics":["async","concurrent","distributed-transactions","python"],"latest_commit_sha":null,"homepage":"","language":"Python","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/meadsteve.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","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":"2018-06-27T18:39:00.000Z","updated_at":"2024-11-07T11:25:46.000Z","dependencies_parsed_at":"2024-10-11T03:20:56.358Z","dependency_job_id":null,"html_url":"https://github.com/meadsteve/talepy","commit_stats":{"total_commits":79,"total_committers":5,"mean_commits":15.8,"dds":"0.44303797468354433","last_synced_commit":"bdf2f81635ac124e1370baa5092114b82fb7d3fb"},"previous_names":[],"tags_count":12,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/meadsteve%2Ftalepy","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/meadsteve%2Ftalepy/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/meadsteve%2Ftalepy/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/meadsteve%2Ftalepy/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/meadsteve","download_url":"https://codeload.github.com/meadsteve/talepy/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244097116,"owners_count":20397545,"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":["async","concurrent","distributed-transactions","python"],"created_at":"2024-10-11T03:10:50.549Z","updated_at":"2025-03-21T01:31:40.053Z","avatar_url":"https://github.com/meadsteve.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Tale Distributed Transactions\n\n[![Build Status](https://travis-ci.org/meadsteve/talepy.svg?branch=master)](https://travis-ci.org/meadsteve/talepy)\n\n## What?\nTale is a small library to help write a \"distributed transaction like\" \nobject across a number of services. It's loosely based on the saga pattern.\nA good intro is available on the couchbase blog: \nhttps://blog.couchbase.com/saga-pattern-implement-business-transactions-using-microservices-part/\n\n## Installation\n```bash\npipenv install talepy\n```\n\n## Example Usage\nAn example use case of this would be some holiday booking software broken\ndown into a few services.\n\nAssuming we have the following services: Flight booking API, Hotel booking API, \nand a Customer API.\n\nWe'd write the following steps:\n\n```python\nfrom talepy.steps import Step\n\nclass DebitCustomerBalance(Step):\n\n    def __init__(self):\n        self.payment_client= {}\n\n    def execute(self, state):\n        state['payment_id'] = self.payment_client.bill(state.customer_id, state.payment_amount)\n        return state\n        \n    def compensate(self, state):\n        self.payment_client.refund(state['payment_id'])\n       \n```\n\nand so on for any of the steps needed. Then in whatever is handling the user's \nrequest a distributed transaction can be built:\n\n```python\nfrom talepy import run_transaction\n\nrun_transaction(\n    steps=[\n        DebitCustomerBalance(), \n        BookFlight(), \n        BookHotel(), \n        EmailCustomerDetailsOfBooking()\n    ],\n    starting_state={}\n)\n```\n\nIf any step along the way fails then the compensate method on each step\nis called in reverse order until everything is undone.\n\n### Steps as Lambdas\n\nFor some cases you may not want to create a class for the step. Lambdas can be used directly \ninstead. Extending the previous example:\n\n```python\nfrom talepy import run_transaction\n\nrun_transaction(\n    steps=[\n        DebitCustomerBalance(), \n        BookFlight(),\n        lambda _: print(\"LOG -- The flight has been booked\"),\n        BookHotel(), \n        EmailCustomerDetailsOfBooking()\n    ],\n    starting_state={}\n)\n```\n\nThis new print statement will now execute following a success in `BookFlight`. \n\nIt's also possible to implement compensations by adding another lambda as a tuple pair:\n\n```python\nfrom talepy import run_transaction\n\nrun_transaction(\n    steps=[\n        DebitCustomerBalance(), \n        BookFlight(),\n        (\n            lambda _: print(\"LOG -- The flight has been booked\"), \n            lambda _: print(\"LOG -- ┌[ ಠ ▃ ಠ ]┐ something went wrong\")\n        ),\n        BookHotel(), \n        EmailCustomerDetailsOfBooking()\n    ],\n    starting_state={}\n)\n```\n\n### Automatic retries\n\nYou may also want to try a step a few times before giving up. A convinence\nfunction is provided to help out with this. Starting with the initial example.\nIf the hotel booking step is a bit unreliable and we want to try it 3 times:\n\n```python\nfrom talepy import run_transaction\nfrom talepy.retries import attempt_retries\n\nrun_transaction(\n    steps=[\n        DebitCustomerBalance(), \n        BookFlight(),\n        attempt_retries(BookHotel(), times=2), \n        EmailCustomerDetailsOfBooking()\n    ],\n    starting_state={}\n)\n```\n\nThe book hotel step will now be executed 3 times before the transaction is aborted. Once\nall these attempts fail the normal compensation logic will be applied.\n\n### Async\n\nIf you want to make use of `async` in your steps you will need to import `run_transaction`\nfrom `talepy.async_transactions`. This can be awaited on and allows async steps and\ncompensations. In addition you can also `run_concurrent_transaction` where all\nsteps will be executed concurrently. The downside here is that the ordering\nof the steps isn't guaranteed. This means all steps receive the same starting state.\n\n#### example\n```python\nfrom talepy.async_transactions import run_transaction\nfrom talepy.steps import Step\n\nclass AsyncBookFlight(Step):\n\n    async def execute(self, state):\n        # do something\n        return state\n        \n    async def compensate(self, state):\n        # revert something\n        pass\n       \n\nawait run_transaction(\n    step_defs=[\n        DebitCustomerBalance(), \n        AsyncBookFlight(),\n        EmailCustomerDetailsOfBooking()\n    ],\n    starting_state={}\n)\n```\n#### Concurrent example\n```python\nfrom talepy.async_transactions import run_concurrent_transaction\nfrom talepy.steps import Step\n\nclass AsyncBookFlight(Step):\n\n    async def execute(self, state):\n        # do something\n        return state\n        \n    async def compensate(self, state):\n        # revert something\n        pass\n       \n\nawait run_concurrent_transaction(\n    steps=[\n        DebitCustomerBalance(), \n        AsyncBookFlight(),\n        EmailCustomerDetailsOfBooking()\n    ],\n    starting_state={}\n)\n```\n\n## Testing / Development\nTODO\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmeadsteve%2Ftalepy","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmeadsteve%2Ftalepy","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmeadsteve%2Ftalepy/lists"}