Reputation: 1135
User on click a purchase button on the web frontend, it will send a POST request to the backend to create a purchase order. First, it will check the number of available
stocks. If available
is greater than 0, reduce available
by 1 and then create the order.
Backend (NestJS) queries the Firestore for the latest available
value, and reduce available
by 1. For debugging, I will return the available
value.
let available;
try {
await runTransaction(firestore, async (transaction) => {
const sfDocRef = doc(collection(firestore, 'items_available'), documentId);
const sfDoc = await transaction.get(sfDocRef);
if (!sfDoc.exists()) {
throw 'Document does not exist!';
}
const data = sfDoc.data();
available = data.available;
if(available>0){
transaction.update(sfDocRef, {
available: available-1,
});
}
});
} catch (e) {
console.log('Transaction failed: ', e);
}
return { available };
Our goal is to see all API requests having different available
value, this would mean that Firestore Transactions is reducing the value even though there are multiple requests coming in.
I wrote a simple multi-threaded program that queries the backend's create order API, it will query the available
value and return the available
value. This program will save the available
value returned for each API request.
The stress test performed is about 10 transactions per second, as I have 10 concurrent processes querying the backend. Each process will http.get
20 queries:
const http = require('http');
function call(){
http.get('http://localhost:5000/get_item_available', res => {
let data = [];
res.on('data', chunk => {
data.push(chunk);
});
res.on('end', () => {
console.log('Response: ', Buffer.concat(data).toString());
});
}).on('error', err => {
console.log('Error: ', err.message);
});
}
for (var i=0; i<20; i++){
call();
}
Unfortunately, the available
values I got from the requests contains repeated values, that is, having same available
values instead of having unique available
values.
What is wrong? Isn't Firestore Transactions meant to handle race conditions? Any suggestions on what I could change to handle multiple requests hitting the server and return a new value for each request?
Upvotes: 0
Views: 303
Reputation: 598718
You have a catch
clause to handle when the transaction fails, but then still end up returning a value to the caller return { available }
. In that situation you should return an error to the caller.
Upvotes: 3