I created a Lambda function that connects to my DynamoDB table and gets the item view_count
and then sets view_count += 1
and then updates the view_count
item and returns view_count
as a string.
When I open the Function URL the first time, it increments view_count
by 1 and outputs 1 which is what I want. But whenever I refresh the page (to simulate another visitor to the website) it always adds 2 more to view_count
instead of 1 more. The item in the table also always shows one more than what is displayed in the function URL.
My Lambda code:
import boto3
import json
def lambda_handler(event, context):
# Connect to DynamoDB
dynamodb = boto3.resource("dynamodb")
table = dynamodb.Table("Table-CRC")
# Get the current view count
response = table.get_item(Key={"id": "1"})
item = response.get("Item", {})
view_count = item.get("view_count", 0)
# Increment the view count
view_count += 1
# Update the view count in DynamoDB
table.put_item(Item={"id": "1", "view_count": view_count})
# Return the updated view count
return {
"statusCode": 200,
"body": str(view_count),
"headers": {
'Content-Type': 'application/json',
}
}
Original setting of the item:
First load of the URL:
What the item changed to:
Second load of the URL (hitting refresh):
What the item changed to after that:
I tried putting the view_count
in the table.get_item
Key statement and removing the two lines under it but that led to an Internal Server Error when I tried to access the Function URL so I think that’s bad code.
2
Answers
Your actually not updating anything, you are overwriting the item everytime by using
put_item
. You want to useupdate_item
which will ensure no issue with race conditions.Some things to note about the code:
We no longer need to do
get_item
as DynamoDB can increment a number for us, this helps us avoid concurrency issues. We don’t set any conditions in our update, as I assume over/under counting can be tolerated for your use-case where your counting webpage hits.We use DynamoDB
update_item
which updates the item and not overwrites it, which again can help any concurrency issues. We return the new values, which returns the item after the update completed so you can return the current value accurately to your client.We moved the DynamoDB initialization outside of the Lambda handler which will improve performance of your Lambda and can also reduce costs for KMS if you use encryption keys.