简体   繁体   中英

Firebase transactions coming back multiple times much later?

This is a fairly weird thing, and it's hard to reproduce. Not the best state of a bug report, I apologize.

I'm using .transaction() to write a value to a location in Firebase. Here's some pseudo-code:

var ref = firebase.child('/path/to/location');

var storeSafely = function(val) {
  ref.transaction(
    function updateFunc(currentData) {
      console.log('Attempting update: ' + JSON.stringify(val));

      if (currentData) return;

      return val;
    },
    function onTransactionCompleteFunc(err, isCommitted, snap) {
      if (err) {
        console.log('Error in onTransactionCompleteFunc: ' + JSON.stringify(err));
        return;
      }

      if (! isCommitted) {
        console.log('Not committed');
        return;
      }

      ref.onDisconnect().remove();
      doSomeStuff();
    });
};

var doSomeStuff = function() {
  // Things get done, time passes.

  console.log('Cleaning up');
  ref.onDisconnect().cancel();
  ref.set(
    null,
    function onSetCompleteFunc(err) {
      if (err) {
        console.log('Error in onSetCompleteFunc: ' + JSON.stringify(err));
      }
    });
};

storeSafely(1);
// later...
storeSafely(2);
// even later...
storeSafely(3);

I'm effectively using Firebase transactions as a sort of mutex lock:

  • Store a value at a location via transaction.

  • Set the onDisconnect for the location to remove the value in case my app dies while working.

  • Do some stuff.

  • Remove the onDisconnect for the location, because I'm done with the stuff.

  • Remove the value at the location.

I do this every few minutes, and it all works great. Things get written and removed perfectly, and the logs show me creating the lock, doing stuff, and then releasing the lock.

The weird part is what happens hours later. Occasionally Firebase has maintenance, and my app gets a bunch of permission denied errors. At the same time this happens, I suddenly start getting a bunch of this output in the logs:

Attempting update 1
Attempting update 2
Attempting update 3

...in other words, it looks like the transactions never fully completed, and they're trying to retry now that the location can't be read any more. It's almost like there's a closure in the transaction() code that never completed, and it's getting re-executed now for some reason.

Am I missing something really important here about how to end a transaction?

(Note: I originally posted this to the Firebase Google Group, but was eventually reminded that code questions are supposed to go to Stack Overflow. I apologize for the cross-posting.)

Just a guess, but I wonder if your updateFunc() function is being called with null when your app gets the permission-denied errors from Firebase. (If so, I could believe that's part of their "Offline Writes" support.)

In any case, you should handle null as a possible state. Saving Transactional Data says:

transaction() will be called multiple times and must be able to handle null data. Even if there is existing data in your database it may not be locally cached when the transaction function is run.

I don't know the intricacies of Firebase's transaction mechansim, but I would try changing your .set(null) to set the value to 0 instead, change your .remove() to also set the value with .set(0) , and change your line in updateFunc() to:

  if (currentData === null || currentData) return;

Unfortunately, that assumes that '/path/to/location' is initially set to 0 at some point. If that's a problem, maybe you can muck around with null versus undefined . For example, it would be nice if Firebase used one of those for non-existent data and another when it's offline.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM