31
loading...
This website collects cookies to deliver better user experience
AccountId | Balance | OverdraftLimit |
---|---|---|
123 | 100 | -500 |
... | ... | ... |
current_version
). You can then locally process the item and make any changes to it. Before you persist your changes, you should increase the version number on the item.PutItem
or UpdateItem
call, but you have to add a ConditionExpression
that checks that the value of the version attribute is still equal to current_version
. This ensures you only update the item if it's in the same state it was in when you first read it. If the condition doesn't hold true, the update/put is cancelled and an exception is raised. You can then read the item again, redo your processing and try writing it to the table.current_version
of the item. Before writing it back, we increment the version number by 1 and then add the condition expression to the put_item
call. The exception handling for the condition check looks a bit clunky, but unfortunately boto3 doesn't expose a "pretty" exception.import boto3
from boto3.dynamodb.conditions import Attr
# Step 0 Init
table = boto3.resource("dynamodb").Table("accounts")
transaction_value = -400 # This would come from somewhere else
# Step 1 Read the current item
item = table.get_item(Key={"AccountId": "123"})['Item']
# This is how item looks like:
# {
# "AccountId": "123",
# "Balance": 100,
# "OverdraftLimit": -500,
# "Version": 0,
# }
current_version = item["Version"]
# Step 2 Apply transaction
if item["Balance"] + transaction_value >= item["OverdraftLimit"]:
item["Balance"] += transaction_value
else:
raise ValueError("Overdraft limit breached!")
# Step 3 Write
# 3.1 Increase the version number so other workers know something changed
item["Version"] += 1
# 3.2 Try to write the item, but only if it hasn't been updated in the mean time
try:
table.put_item(
Item=item,
ConditionExpression=Attr("Version").eq(current_version)
)
except ClientError as err:
if err.response["Error"]["Code"] == 'ConditionalCheckFailedException':
# Somebody changed the item in the db while we were changing it!
raise ValueError("Balance updated since read, retry!") from err
else:
raise err