I have a function that is decrementing user credits on firebase realtime database values with a transaction. As suggested in Firebase transaction API call current data is null transaction current value occasionally returns as null.
I've made a guard for the null case and returned 0 so the transaction function fires again until it gets the actual credit value.
function charge(cost, description) {
return new Promise((resolve, reject) => {
const creditRef = db.ref(`credits/${userid}`)
ref.transaction(function(current) {
console.log(`${description} current value: ${current}`)
if (current === null) {
console.log(`${description} returns 0 `)
return 0
}
if (cost > current || current === 0) {
//not enough credits return without committing
console.log(`${description} aborts `)
return
}
//commit the new credit value
console.log(`${description} returns ${current} - ${cost}`)
return current - cost
},
(error, commited, snapshot) => {
if (error) {
reject(error)
}
else {
if (commited) {
//user has enough credits
resolve()
}
else {
//not enough credits
reject('no commit')
}
}
})
}
However, in a case where 2 charge functions are fired back to back, the second call will get a current value of 0 (which is probably the returned 0 on the first charge call). So it will prematurely exit assuming that the user doesn't have enough credits. When both functions resolve the final credit value will be 3 and the second charge call will be ignored.
// User has 5 credits
charge(3, 'first call').then(() => console.log('first call success')
// transaction function returns 0 since current value is null
charge(2, 'second call').then(() => console.log('second call success')
Console log output:
first call current value: null
first call returns 0
second call current value: 0
second call aborts
first call current value: 5
first call returns 5 - 3
first call success
second call no commit
So the second charge call ends up not going through when user had enough credits. What is the proper way to handle firebase transaction null value cases?