This is a tricky one, after a painful day of debugging I eventually stopped debugging my code and wrote the following test case.
Please consider the following code:
for (var i = 0; i < 10; i++) {
(function(bidderId){
firebase.database().ref('counter').transaction(function (currentValue) {
if (!currentValue) {
return 1;
} else {
if (currentValue >= 5) {
return;
} else {
return currentValue + 1;
}
}
}, function(error, committed, snapshot){
if (error){
console.error(error);
}
if (committed){
console.log(bidderId + ' successful');
} else {
console.log(bidderId + ' not successful');
}
var updates = {};
updates['user/' + bidderId+'/success'] = committed;
firebase.database().ref().update(updates);
});
})(i);
}
When I run this from a Node JS server (v4.4.3) with Firebase JS SDK v3.1.0 I see the following out put on the terminal:
node transaction.js
5 not successful
[Error: set]
1 not successful
[Error: set]
2 not successful
[Error: set]
3 not successful
[Error: set]
4 not successful
0 successful
[Error: set]
7 not successful
[Error: set]
8 not successful
[Error: set]
9 not successful
6 successful
In the firebase console I inspect the counter and it has a value of 2 which corresponds to the two successful commits that were reported.
Why does the [Error: set] occur here?
I am trying to write a transaction that increments a counter up to a certain maximum value, in this case 5 and then writes to another firebase location to indicate that the attempted increment (whether successful or not) has finished. Imagine I have a bidding system that allows up to 5 bids for a product and needs to indicate to the bidder if their bid constituted one of the 5 allowed.
Observations:
(1) when I remove the line firebase.database().ref().update(updates); everything works as expected; the console output is then:
$ node transaction.js
5 not successful
6 not successful
7 not successful
8 not successful
9 not successful
0 successful
1 successful
2 successful
3 successful
4 successful
... and the counter is correctly incremented to 5. However this does not leave me with any way to indicate success or failure to the bidder.
(2) If I change the following (keeping the call to the .update() function in place):
if (currentValue >= 5) {
return;
}
to
if (currentValue >= 5) {
return currentValue;
}
it works, but I get multiple unnecessary commits as follows:
node transaction.js
0 successful
1 successful
2 successful
3 successful
4 successful
5 successful
6 successful
7 successful
8 successful
9 successful
The counter is only incremented to value 5, however all bids are reported as successful.
(3)
If I try to enclose the call to update in a short timeout as follows:
setTimeout(function(){
var updates = {};
updates['user/' + bidderId+'/success'] = committed;
firebase.database().ref().update(updates);
},200)
I still have the same problem. However if I increase the timeout to 2000 then everything works as expected - the counter is incremented to 5 and the /success firebase locations are updated appropriately.
(4)
If I use the .set() function instead of the .update() function as follows:
firebase.database().ref('user/' + bidderId+'/success').set(committed);
... everything also works as expected.
I actually need to make several atomic updates here, which is why I am using the .update() method in the first place - so my main questions still stands - why does the .update() function not work in the context of a transactions onComplete() callback, even when it is writing to an entirely different firebase location that that which the transaction itself is pointing to.
P.S. the full stack for the [Error: set] message above is as follows:
Error: set
at Error (native)
at ji (/Users/-------/node_modules/firebase/database-node.js:227:346)
at /Users/-------/node_modules/firebase/database-node.js:226:104
at jh (Users/-------/node_modules/firebase/database-node.js:180:196)
at /Users/-------/node_modules/firebase/database-node.js:180:217
at /Users/-------/node_modules/firebase/database-node.js:180:148
at v (/Users/-------/node_modules/firebase/database-node.js:10:370)
at fh.g.P (/Users/-------/node_modules/firebase/database-node.js:180:116)
at jh (/Users/-------/node_modules/firebase/database-node.js:180:203)
at ai (/Users/-------/node_modules/firebase/database-node.js:226:87)
I would very much appreciate your help on this.
Thanks for reading.
Alex