{"id":22191250,"url":"https://github.com/farbodahm/dynamodb-optimistic-locking","last_synced_at":"2025-03-24T20:42:36.030Z","repository":{"id":218343945,"uuid":"746175897","full_name":"farbodahm/dynamodb-optimistic-locking","owner":"farbodahm","description":"A simple project to implement optimistic locking (using versioning) on DynamoDB.","archived":false,"fork":false,"pushed_at":"2024-02-02T17:11:30.000Z","size":662,"stargazers_count":1,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-01-30T01:15:34.489Z","etag":null,"topics":["dynamodb","optimistic-locking","race-condition"],"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/farbodahm.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":"2024-01-21T09:46:19.000Z","updated_at":"2024-02-01T18:16:31.000Z","dependencies_parsed_at":"2024-01-31T21:38:38.819Z","dependency_job_id":"4f518ca0-c86a-45f9-8d7b-170ffd03c033","html_url":"https://github.com/farbodahm/dynamodb-optimistic-locking","commit_stats":null,"previous_names":["farbodahm/dynamodb-optimistic-locking"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/farbodahm%2Fdynamodb-optimistic-locking","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/farbodahm%2Fdynamodb-optimistic-locking/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/farbodahm%2Fdynamodb-optimistic-locking/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/farbodahm%2Fdynamodb-optimistic-locking/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/farbodahm","download_url":"https://codeload.github.com/farbodahm/dynamodb-optimistic-locking/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245351759,"owners_count":20601088,"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":["dynamodb","optimistic-locking","race-condition"],"created_at":"2024-12-02T12:15:04.353Z","updated_at":"2025-03-24T20:42:35.997Z","avatar_url":"https://github.com/farbodahm.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Dynamodb Optimistic Locking\n\nThis is a simple project written in a weekend to \nimplement optimistic locking (versioning model) on DynamoDB.\n\n## Problem statement\n\nAssume we have a table called `products` on DynamoDB. One of the attributes is `quantity` showing the number of available products in the wharehouse.\n\nNow assume different users order the same product concurrently,\nresulting in race condition. How would you fix this problem?\n\n- Assume that we are not serializing the requests in one\nGoroutine (or in one thread, in generic);\neach request is handled by one Goroutine concurrently.\n- Special edge case of this problem, will be scenario\nwhere we have only 1 product available in the wharehouse;\nbut 2 users order that exactly at the same time.\n\n![dynamodb-race-condition](./docs/update-no-condition.png)\n\n## Solution\n\nBy default, DynamoDB is not ACID complient. But with a\ncorrect combination of [Transactional Write](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/transaction-apis.html)\nand\n[Conditional Write](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/WorkingWithItems.html#WorkingWithItems.ConditionalUpdate)\nwe can achieve a similar behavour.\n\n### Architecture\n\nOne of the easiest ways to solve this problem is\nto use [Optimistic Locking](https://en.wikipedia.org/wiki/Optimistic_concurrency_control)\nimplemented with Conditional Write.\n\n1. To achieve this, we can add a `version` attribute\n(with a default value of 1) to the table.\n2. All of the requests, get the same item from DynamoDB.\n3. Next to the change each request want to do with the item,\nthey should also bump the `version` by +1. Ex: if the previous\nversion was 1, it will become 2 locally.\n4. All of the threads can now send the update request; with\nthe following condition expression: `version = oldVersion`.\n    - Only request for one of the threads will be accepted\nand every other request will be rejected as the version is\nupdated and is not equal to the old value.\n\nA picture is worth a thousand words:\n![dynamodb-optimistic-lock](./docs/update-with-condition.png)\n\n## How to run the project\n\n### Creating the table\n\nMake sure you have [Terraform](https://www.terraform.io/) installed.\nThen easily create the table using:\n\n```hcl\ncd infra/\nterraform init\nterraform apply\n```\n\n**Note:** Make sure your IAM role has the correct permissions\nto create DynamoDB table and has read/write access on that table.\n\n### Running the application\n\nFirst thing first, build the application:\n\n```go\ngo mod tidy\ngo build\n```\n\nThen to populate the table, you can easily provide the\n`--populate-table` so the script will populate the table\nwith sample data for you:\n\n```sh\n./dynamodb-optimistic-locking --populate-table\n```\n\n**Note:** You can skip this part if you don't want to populate\nthe table with sample data.\n\nand to run the application:\n\n```sh\n./dynamodb-optimistic-locking --number-of-requests 100\n```\n\nThis will simulate submitting 100 orders simultaneously, which\nif everything goes well, 99 of them should fail:\n![result](./docs/result.png)","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffarbodahm%2Fdynamodb-optimistic-locking","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffarbodahm%2Fdynamodb-optimistic-locking","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffarbodahm%2Fdynamodb-optimistic-locking/lists"}