Lahiru Chandima
Lahiru Chandima

Reputation: 24068

Firebase realtime database transaction handler gets called twice most of the time

I am using transactions to write to a specific location in firebase realtime database with firebase admin api in my nodejs app. I observed that the transaction handler gets called twice, even when there are no other clients using the database.

Following is a minimal code which displays this behavior.

firebaseAdmin.database().ref('some/path').transaction(currentData => {
    console.log('transaction handler got called');
    return {'abc': 'def'};
}, null, false).then(value => {
    console.log('transaction complete')
}).catch(reason => {
    console.log('transaction failed. ' + reason);
});

I can observe that transaction handler got called gets logged twice for each execution of above code.

I understand that the handler can get called multiple times if some other client writes to the db path in the window between currentData is read for a transaction and the new data is attempted to be committed to the db path. But, there are no other clients in my case, so I cannot understand why the transaction handler needs to get called twice.

Does anyone know what is the reason for this?

Upvotes: 5

Views: 1456

Answers (1)

Frank van Puffelen
Frank van Puffelen

Reputation: 598728

This is expected behavior. When you run a transaction, the Firebase client immediately calls your transaction handler with its best guess of the current value of some/path. The first time you run it, this best guess is typically null. If some/path already exists that is always wrong, and will always lead to a second call to your transaction handler once the client has the correct current value.

In a flow chart it looks something like this

 app code   client                   server
              +                         +
transaction() |                         |
              |+--+                     |
              |   |current == null      |
              |   v                     |
              |   |new = 0              |
              |<--+                     |
              |                         |
              |  current==null, new=0   |
              |+----------------------->|
              |                         |+--+
              |                         |   |current != null
              |                         |   v
              |                         |   |current = 0
              |                         |<--+
              |    NACK, current=0      |
              |<-----------------------+|
              |                         |
              |+--+                     |
              |   |curent==0            |
              |   v                     |
              |   |new=1                |
              |<--+                     |
              |                         |
              |  current==0, new=1      |
              |+----------------------->|
              |                         |+--+
              |                         |   |current == 0
              |                         |   v
              |                         |   |current = 1
              |                         |<--+
              |    ACK, current=1       |
              |<-----------------------+|
              |                         |
              +                         +

Also see these explanations of how transactions work:

Upvotes: 7

Related Questions