Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Why is a transaction in my Firebase Cloud function not able to retrieve data which exists and thus, failing?

In my 2nd generation cloud function i have the following code:

export const roomEnter = functions.https.onCall(async (request: any) => {

  // initial validation to verify user authentication and valid request data passes first
  ...

  const roomRef = admin.database().ref(`rooms/${request.data.roomId}`);
  const roomSnapshot = await roomRef.once("value");
  const testDataExists = {
    exists: roomSnapshot.exists(),
    data: roomSnapshot.val()
  };
  functions.logger.log("[room enter] CHECK ROOM EXISTS:", JSON.stringify(testDataExists));

  // In the logs, the data that exists DOES print to the console successfully

  const transactionRef = admin.database().ref(`rooms/${request.data.roomId}`);
  const transactionResult = await transactionRef.transaction((currentData) => {
    functions.logger.log("[room enter] Transaction current data:", JSON.stringify(currentData));

    // In the logs, `currentData` prints as `null`, why?
    // As a result, the transaction never gets beyond this condition and fails i assume after it has exhausted all internal retries

    if (currentData !== null) {
      if (currentData.memberTotal) {
        currentData.memberTotal += 1;
      } else {
        currentData.memberTotal = 1;
      }
      return currentData;
    } else {
      functions.logger.log("[room enter] Transaction needs to retry, room current data is null", {
        roomId: request.data.roomId
      });
      return; // Returning undefined should cause Firebase to retry the transaction
    }
  });

  if (transactionResult.committed) {
    // never able to reach this point
  } else {
    functions.logger.log("[room enter] transaction to increment member total failed");
    throw new functions.https.HttpsError("internal", "transaction to increment member total failed", {
      customData: {
        roomId: request.data.roomId
      }
    });
  }

  ...
});

The test query i do immediately prior to the transaction is only there as a test to confirm the data exists.

And as noted in the code comments above, the transaction fails despite the reference path to existing data having been confirmed to exist.

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

Other than attempting to log errors everywhere possible, i am not sure how to troubleshoot this issue.

Other cloud functions i have which do not use transactions are able to read and write to the database without issue.

The only additional info i have aside from the logs, is that client side the error is reported to the client as a 500 internal server error along with the response which does include the error response containing the message transaction to increment member total failed.

With respect to my database security rules, as a test, in-order to rule this out as the cause i have set ".write": true for rooms and rooms/$roomId

So, why is currentData null inside the transaction?
What else can i do to troubleshoot?

>Solution :

Firebase Realtime Database transaction handlers will almost always be called with a null value in the mutable data initially, no matter what the actual value in the database is.

This is because the SDK immediately calls your handler with its best guess to the current value, and that’ll usually be null. Your code will need to handler this situation, so that the SDK can then send the null-and-new-value to the server, realize that its guess was wrong, and try again.

This has been covered quite a few times over the years, and probably explained better in some of those cases than I did here, so I recommend checking out:

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading