Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cloud Functions for Firebase database onWrite triggered twice

Hi I am developing a notification system, but I am having trouble deleting the processed notification data. The onWrite event listener is triggered twice resulting to two notifications.

Can you help me find a work around so that onWrite event listener should not be triggered twice? It is important to delete the processed data.

exports.sendMessageNotification = functions.database.ref('/notification/message/{recipientUid}/{senderUid}').onWrite(event => {
/* processing notification and sends FCM */

return admin.messaging().sendToDevice(tokens, payload).then(response => {
      // For each message check if there was an error.
      const toRemove = [];
      response.results.forEach((result, index) => {
        const error = result.error;
        if (error) {
          console.error('Failure sending notification to', tokens[index], error);
          // Cleanup the tokens who are not registered anymore.
          if (error.code === 'messaging/invalid-registration-token' ||
              error.code === 'messaging/registration-token-not-registered') {
            toRemove.push(tokensSnapshot.ref.child(tokens[index]).remove());
          }
        }
      });

      //Deletes processed notification
      console.log("Removing notification");
      const getNotificationPromise = admin.database().ref(`/notification/message/${recipientUid}/${senderUid}`).once('value');
      return Promise.all([getNotificationPromise]).then(results => {
        const notificationSnapshot = results[0];
        toRemove.push(notificationSnapshot.ref.remove());

        console.log("Removing tokens.")
        return Promise.all(toRemove);
      });
      //return Promise.all(tokensToRemove);
    });
});

})
like image 240
Lester Avatar asked Jan 05 '23 06:01

Lester


1 Answers

This is a common mistake. You are writing back into the same database location (by removing the data) that was matched when the function first triggered. This means that removal will be triggering the function again to handle that second change. This is currently the expected behavior.

You will need to come up with a way to detect that the second write happened in response to the removal of data. Also, you are currently doing too much work in your function. There's no need to read the value of the database at '/notification/message/{recipientUid}/{senderUid}' - it is already being delivered to you in the event that's passed to the function. Be sure to read the docs about database triggers. You can know if the function was triggered a second time by examining the event data and returning early if it's null, which means it was removed.

Also, you don't need Promise.all() if you are dealing with a single promise. Just use then() on that single promise to continue processing, or return that single promise from then().

You might want to look at some of the sample code that shows database triggers.

like image 175
Doug Stevenson Avatar answered Jan 13 '23 11:01

Doug Stevenson