AI found the concurrency bug in this code, then fixed it
Fixing distributed system bugs with the assistance of Amazon Q Developer
- Fetch the current value of the counter from some shared state store, such as your database
- Increment the value
- Store the incremented counter back into the shared state store


- Each of the three concurrent page views fetches the current value of the counter at the time of the page load. All three page views observe an initial page view count of
42
. - Each of the three operations increments their own local copy of the value
42
to43
. - Each of them saves the value back to the central store of truth as
43
.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
app.get('/count', async (req, res) => {
// Get current count from DynamoDB table counters
const data = await client.send(new GetItemCommand({
TableName: "counters",
Key: {
"id": {
S: "hit-counter"
}
}
}));
let count;
if (!data.Item) {
count = 0;
} else {
count = data.Item.count.N;
}
// Increment the count
count++;
// Update DynamoDB table with new count.
await client.send(new UpdateItemCommand({
TableName: "counters",
Key: {
"id": {
S: "hit-counter"
}
},
UpdateExpression: "SET count = :newCount",
ExpressionAttributeValues: {
":newCount": {
N: count
}
}
}));
res.statusCode = 200;
res.setHeader('Content-Type', 'text/plain');
res.end(count);
})
I’m trying to build a hit counter. Why is this code not keeping track of hits properly?

Concurrency issues - If multiple requests are hitting the endpoint simultaneously, it's possible the counts could get overwritten or missed. DynamoDB supports atomic increment/decrement operations that can help avoid this.
Use DynamoDB's atomic counter operation instead of a separate Get/Update
UpdateItemCommand
approach, and Amazon Q gave me the following rewritten piece of code:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
app.get('/count', async (req, res) => {
const data = await client.send(new UpdateItemCommand({
TableName: "counters",
Key: {
"id": {
S: "hit-counter"
}
},
UpdateExpression: "SET #count = if_not_exists(#count, :initial) + :increment",
ExpressionAttributeNames: {
"#count": "count"
},
ExpressionAttributeValues: {
":initial": {N: "0"},
":increment": {N: "1"}
},
ReturnValues: "ALL_NEW"
}));
const count = data.Attributes.count.N;
res.statusCode = 200;
res.setHeader('Content-Type', 'text/plain');
res.end(count);
})
Want to learn more about how to use Amazon Q in your day to day work as a software builder? Find more tips and tricks in the Amazon Q Developer Center.
Any opinions in this post are those of the individual author and may not reflect the opinions of AWS.