{ "info": { "author": "Steve Brazier", "author_email": "meadsteve@gmail.com", "bugtrack_url": null, "classifiers": [ "Development Status :: 4 - Beta", "Programming Language :: Python", "Programming Language :: Python :: 3" ], "description": "# 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 -- \u250c[ \u0ca0 \u2583 \u0ca0 ]\u2510 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 continence\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 can use `run_async_transaction`\ninstead. This behaves slightly differently to `run_transaction` as the ordering\nof the steps isn't guaranteed. This means all steps receive the same starting state.\n\n```python\nfrom talepy.parallel import run_async_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_async_transaction(\n steps=[\n DebitCustomerBalance(), \n AsyncBookFlight(),\n EmailCustomerDetailsOfBooking()\n ],\n starting_state={}\n)\n```\n\n## Testing / Development\nTODO", "description_content_type": "text/markdown", "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/meadsteve/talepy", "keywords": "saga,distributed transaction", "license": "", "maintainer": "", "maintainer_email": "", "name": "talepy", "package_url": "https://pypi.org/project/talepy/", "platform": "", "project_url": "https://pypi.org/project/talepy/", "project_urls": { "Homepage": "https://github.com/meadsteve/talepy" }, "release_url": "https://pypi.org/project/talepy/0.7.1/", "requires_dist": null, "requires_python": "", "summary": "Distributed Transactions Helper", "version": "0.7.1" }, "last_serial": 5200326, "releases": { "0.1.0": [ { "comment_text": "", "digests": { "md5": "47547583825016634095824eb496c5d2", "sha256": "a8a1025069d1be429b39ab9f8eecf0a38d815442830cf1c0654b9ae6b4226bd2" }, "downloads": -1, "filename": "talepy-0.1.0.tar.gz", "has_sig": false, "md5_digest": "47547583825016634095824eb496c5d2", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 1061, "upload_time": "2018-07-02T20:32:18", "url": "https://files.pythonhosted.org/packages/2d/59/72627181ea767fbc9f6c744a3249c780c494fe5054404a030a7db2ea4a40/talepy-0.1.0.tar.gz" } ], "0.1.1": [ { "comment_text": "", "digests": { "md5": "f40d84492a344ed7dc775d1440419bce", "sha256": "48eeaadecff5229613d53aaef81eef30dc924e2ca2a1a7a53da7fad4187a1a04" }, "downloads": -1, "filename": "talepy-0.1.1.tar.gz", "has_sig": false, "md5_digest": "f40d84492a344ed7dc775d1440419bce", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 1140, "upload_time": "2018-07-04T18:42:59", "url": "https://files.pythonhosted.org/packages/79/13/b5eb79686c79404256b2762c9eff752b32ef334b3e76cd116f8155d6f30f/talepy-0.1.1.tar.gz" } ], "0.2.0": [ { "comment_text": "", "digests": { "md5": "226da082368903284686f3d002007eb0", "sha256": "510ee153861f3268b59dceeb3b6fe84bcf334c38960a620e27e2b92cf394e31e" }, "downloads": -1, "filename": "talepy-0.2.0.tar.gz", "has_sig": false, "md5_digest": "226da082368903284686f3d002007eb0", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 2167, "upload_time": "2018-07-04T19:04:59", "url": "https://files.pythonhosted.org/packages/8b/12/5eb74e9c2213afa83e4a7eb74593358d95e74c493ed2e662a03766810edb/talepy-0.2.0.tar.gz" } ], "0.2.1": [ { "comment_text": "", "digests": { "md5": "32dba6b3725e7085df16c0a688f8fcd8", "sha256": "c020505e015f042b8d1ddd86b2a7ca8795e0a981f333f2a69745827e05d48bf1" }, "downloads": -1, "filename": "talepy-0.2.1.tar.gz", "has_sig": false, "md5_digest": "32dba6b3725e7085df16c0a688f8fcd8", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 2410, "upload_time": "2018-07-04T19:21:10", "url": "https://files.pythonhosted.org/packages/7b/ae/321b7036037c9f70a4b7a39299857040f359407a9023d1315fedbdd0e4dd/talepy-0.2.1.tar.gz" } ], "0.4.0": [ { "comment_text": "", "digests": { "md5": "1d07e79696f72b80a28d3b83a2a9e1f3", "sha256": "0f5cc341cb0531b82cb3868e9cd3eb15707cf447d46dc14a069297ea8598788d" }, "downloads": -1, "filename": "talepy-0.4.0.tar.gz", "has_sig": false, "md5_digest": "1d07e79696f72b80a28d3b83a2a9e1f3", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 2752, "upload_time": "2018-07-04T20:25:28", "url": "https://files.pythonhosted.org/packages/9b/b3/1b650f0cf9340514541a83bef020241747d23c7ee2c64a81c039359dd073/talepy-0.4.0.tar.gz" } ], "0.5.0": [ { "comment_text": "", "digests": { "md5": "51b8cd1e21678c8be341c3e7702f526d", "sha256": "e2d486da96656c75d8430488086cbba6d229a1d28c1c50f9c4d75dfe0fb585ba" }, "downloads": -1, "filename": "talepy-0.5.0.tar.gz", "has_sig": false, "md5_digest": "51b8cd1e21678c8be341c3e7702f526d", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 2887, "upload_time": "2018-07-05T19:23:02", "url": "https://files.pythonhosted.org/packages/f1/bd/b42a9bc6201bcf4e46fde8f8d9ed12fc7d8b7e091b97f155a01bf11d32f2/talepy-0.5.0.tar.gz" } ], "0.6.0": [ { "comment_text": "", "digests": { "md5": "fe60d0bf01dfa1e134432de400819ade", "sha256": "ec1d9964142b0834d6cea9216e1e7b973fb1b8f233b76cd549e516f9f32f93b4" }, "downloads": -1, "filename": "talepy-0.6.0.tar.gz", "has_sig": false, "md5_digest": "fe60d0bf01dfa1e134432de400819ade", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 4194, "upload_time": "2018-09-12T13:47:18", "url": "https://files.pythonhosted.org/packages/44/74/da88c3c18d989de8ec8f730ec01903ff6f6b47205d8749af95a23d572641/talepy-0.6.0.tar.gz" } ], "0.6.1": [ { "comment_text": "", "digests": { "md5": "7c9b415639ea183cf98c61e946b7c53f", "sha256": "e8b4046d32ac3ee585a35769543d4951418ea9b5db03146a4581d4aea979654c" }, "downloads": -1, "filename": "talepy-0.6.1.tar.gz", "has_sig": false, "md5_digest": "7c9b415639ea183cf98c61e946b7c53f", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 4216, "upload_time": "2018-11-02T08:07:52", "url": "https://files.pythonhosted.org/packages/df/87/88876721559b02040c828f7f2f09dcb520635f58ae1b394826d2f82155b7/talepy-0.6.1.tar.gz" } ], "0.6.2": [ { "comment_text": "", "digests": { "md5": "613fa23ae1ab971adb0f3aaaf47efdc7", "sha256": "10305f370b244c17f390a33c60804f5df11802087e47c2ecc66dcf547ee8257b" }, "downloads": -1, "filename": "talepy-0.6.2.tar.gz", "has_sig": false, "md5_digest": "613fa23ae1ab971adb0f3aaaf47efdc7", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 4256, "upload_time": "2019-04-26T07:56:36", "url": "https://files.pythonhosted.org/packages/68/63/3f0280f5136cffe68178dd30df7982d92be320ac18ce13a4fdbef4b3e3a9/talepy-0.6.2.tar.gz" } ], "0.7.0": [ { "comment_text": "", "digests": { "md5": "5f67632cc44916871b7b4ec443b68ea9", "sha256": "38b59a77dfb18f936804ab22fc552f3bbe76d57cc36bbe91679e8b5a585f9aed" }, "downloads": -1, "filename": "talepy-0.7.0.tar.gz", "has_sig": false, "md5_digest": "5f67632cc44916871b7b4ec443b68ea9", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 5082, "upload_time": "2019-04-28T11:50:01", "url": "https://files.pythonhosted.org/packages/aa/80/274df05cc246d9f78e933c41ac5b54643ed8f51d665477c3a35a3175d405/talepy-0.7.0.tar.gz" } ], "0.7.1": [ { "comment_text": "", "digests": { "md5": "6bc184613d1468bfb5a630bf2555123c", "sha256": "7423739dba5673f35d2fd2e96f03aad276df712d78406e703e15cbda4b948e5e" }, "downloads": -1, "filename": "talepy-0.7.1.tar.gz", "has_sig": false, "md5_digest": "6bc184613d1468bfb5a630bf2555123c", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 5250, "upload_time": "2019-04-28T18:32:07", "url": "https://files.pythonhosted.org/packages/d0/83/9ea17b22828cc57d98afbed3715f03a1e0b9c20de62b305d8fd906d3e826/talepy-0.7.1.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "6bc184613d1468bfb5a630bf2555123c", "sha256": "7423739dba5673f35d2fd2e96f03aad276df712d78406e703e15cbda4b948e5e" }, "downloads": -1, "filename": "talepy-0.7.1.tar.gz", "has_sig": false, "md5_digest": "6bc184613d1468bfb5a630bf2555123c", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 5250, "upload_time": "2019-04-28T18:32:07", "url": "https://files.pythonhosted.org/packages/d0/83/9ea17b22828cc57d98afbed3715f03a1e0b9c20de62b305d8fd906d3e826/talepy-0.7.1.tar.gz" } ] }