I have implemented a counter variable in my real time database, the users are able to call the function and upon 4 calls it should run some code.
The problem is that it may take too long to run and update the counter, so if the counter = 1 and two people call the function at a relative same time both of them
will get
datasnapshot.child("counter").val() = 1
and both of them will set
promises.push(admin.database().ref('game/' + matchkey + '/counter').set((counter + 1))) = 2
while it should be 3
how can I fix this ? (I guess by either making the update faster or forcing the function to wait for the previous one to end (not sure if possible), or something else that I am missing I am new to firebase & ts)
this is my code:
exports.functionTST = functions.https.onCall(async (data, context) => {
const promises = [];
JSON.parse(JSON.stringify(data), (key, value) => {
parse values
});
//set values
promises.push(admin.database().ref('game/' + matchkey + '/'...).update({
val1: val2,
}))
//counter
admin.database().ref('game/' + matchkey).once('value')
.then(datasnapshot => {
let counter = datasnapshot.child("counter").val()
if (counter === null) {
promises.push(admin.database().ref('game/' + matchkey + '/counter').set(1))
} else if (counter < 3) {
promises.push(admin.database().ref('game/' + matchkey + '/counter').set((counter + 1)))
} else if (counter == 3) {
promises.push(admin.database().ref('game/' + matchkey + '/counter').remove())
//do other stuff
}
});
Promise.all(promises);
return null
}
});
Thanks !!
2
Answers
First run after deploy take time because the cold start happening, And consider using transaction to prevent race condition.
First, let’s fix your indentation.
From this, we can now see a few issues.
The most notable error, is that you aren’t awaiting or returning the
Promise
chain properly. When you don’t wait for the promises to resolve, your function will get severely throttled and network requests (such as updating the database) can be skipped entirely.should be
or
This next block of code does nothing useful. Were you meant to store the result of
JSON.parse
into a new variable? Depending on what you are trying to achieveObject.entries(data)
might be a better choice.This next block of code spawns a floating
Promise
– you aren’t returning it, nor are you storing it into an array likepromises
– so it will cause inconsistent behaviour (like never updating the counter).The entirety of the code shown in this block should be replaced by a transaction operation instead to streamline the database updates and ensure that it is properly updated.
Adapting the transaction example and merging your other logic gives:
After implementing the above block, your function can become something similar to:
To ensure that the function returns appropriate errors, you should surround each part in try-catch blocks and throw an appropriate
HttpsError
so failures can be handled gracefully by the caller on the client side: