I built an Online Shop Website with Mongo DB and Express.js that has flash sale features on it. Its traffic spiked when it came to the Flash Sale, with 5,000 users per minute.
As we know, in the online shop, every product has available stock. My problem is, for every high-traffic visitor, I encounter minus stock. I think this happens because of race conditions. Some visitors (let’s say 5 visitors) have current stock as 1 left, so the logic tells that they can buy the product, and then when the transaction is successful, the stock is subtracted by 5, which makes the minus data ( 1 – 5 = -4 ). This was my code.
const product = await this.productService.findOne(slug)
if( !product )
return res.status(404).json({ success: false, message: 'Not Found' })
if( product.available <= 0 )
return res.json({ success: false, message: 'Out of Stock' })
const newTransaction = await this.transactionService.create(user, product)
await this.productService.update(product.id, { available: product.available - 1 })
return res.json({ success: true, data: newTransaction })
But, then I realised minus data occurred at the field available
so Here is my current code.
await sleep(200, 500) // I want to random the sleep time, so I made a function that can random the sleep time with args min, max in milliseconds
const product = await this.productService.findOne(slug)
if( !product )
return res.status(404).json({ success: false, message: 'Not Found' })
if( product.available <= 0 )
return res.json({ success: false, message: 'Out of Stock' })
const newTransaction = await this.transactionService.create(user, product)
await this.productService.update(product.id, { available: product.available - 1 })
return res.json({ success: true, data: newTransaction })
My current code temporarily solves my issues. But, when it comes to very high traffic the minus happens again (but not much than the first code, it can reduce the 80-90% minus value) but it still happens.
Currently, I can’t reproduce the bugs, because it will need 2000-5,000 requests hit to my endpoint at the same time to make the minus occur.
Does anyone have any idea what alternative that can I try to solve this issue? Or tools that can reproduce that many requests for one endpoint.
2
Answers
Two things come to my mind:
For reproducing traffic there are a lot of tools like jMeter so pick the one that fits you i guess.
You need to implement a proper locking mechanism to ensure that only one request at a time can modify the stock of a product. One common approach is to use a database transaction to ensure atomicity and consistency of the stock update operation.I strongly recommend you look into Database Concurrency Control and transactions. I will give you a possible solution, but please remember it’s just one of many approaches. Take it as an idea and you will need to find the approach that is most suitable for your use-case. Also I will strongly recommend that you test your solution under simulated high traffic.