0

I am using Firebase Cloud Functions, which get triggered by the creation of a document in Firestore. On creation of the object, I need to undertake two different operations in parallel:

  1. update the value of a field in a specific document (not the one which was created and triggered the cloud function)
  2. run a transaction on another document.

So my questions are:

  1. How do I ensure that both of my operations have been successfully completed before ending the cloud function itself?
  2. How do I implement separate retry mechanism for each of the two operations (as I do not want a common retry mechanism for the whole function as it can redo the transaction operation even if it was the other operation that had failed)?

Here is my current code:

exports.onCityCreated = functions.firestore
    .document('Cities/{cityId}')
    .onCreate((snap, context) => {
        const db = admin.firestore(); 
        const newCity = snap.data();
        const mayorId = newEvent.mayorID;
        const mayorRef = db.doc('Users/'+ mayorId);

        const timestamp = admin.firestore.FieldValue.serverTimestamp();
        db.doc('Utils/lastPost').update({timestamp: timestamp});    //First Operation - Timestamp Update

        return db.runTransaction(t => {    //Second Operation - Transaction
                return t.get(mayorRef).then(snapshot => {
                    var new_budget = snapshot.data().b - 100;
                    return t.update(mayorRef, {b: new_budget});
                })
            .then(result => {
                return console.log('Transaction success!');
            })
            .catch(err => {
                console.log('Transaction failure:', err);
            });
        });
});
Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
Aayush Taneja
  • 511
  • 7
  • 18

1 Answers1

2

Whenever you have multiple operations like this, the solution is to use Promise.all(). This takes an array of promises, and in turn returns a promise that resolves when all promises you passed in are resolved.

exports.onCityCreated = functions.firestore
    .document('Cities/{cityId}')
    .onCreate((snap, context) => {
        const db = admin.firestore(); 
        const newCity = snap.data();
        const mayorId = newEvent.mayorID;
        const mayorRef = db.doc('Users/'+ mayorId);

        const timestamp = admin.firestore.FieldValue.serverTimestamp();
        var p1 = db.doc('Utils/lastPost').update({timestamp: timestamp});

        var p1 = db.runTransaction(t => {
                return t.get(mayorRef).then(snapshot => {
                    var new_budget = snapshot.data().b - 100;
                    return t.update(mayorRef, {b: new_budget});
                })
        });
        return Promise.all([p1, p2]);
});
Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
  • 1
    Thanks. It works. Now, what if an operation fails, how do I get to know which operation failed. And what if both of them fail? Also, how can I implement a separate retry mechanism for each of them? – Aayush Taneja Sep 09 '18 at 14:34
  • I don't think `Promise.all()` exposes enough information to determine what promise failed. Have a look at https://stackoverflow.com/questions/30362733/handling-errors-in-promise-all. – Frank van Puffelen Sep 09 '18 at 14:43