Search code examples
node.jsfirebasegoogle-cloud-platformgoogle-cloud-firestoregoogle-cloud-functions

How can I optimize my Cloud Function to react to Firestore document status changes more efficiently?


How can I optimize my Cloud Function to react to Firestore document status changes more efficiently? Is there a way to make this process event-driven rather than using periodic checks? I'm looking for a method that minimizes Firestore reads/writes and reduces the latency and costs associated with polling. Imagine that I launch a program and two processes are initiated:

  1. The first process continuously checks if the status of a document has changed; if so, it stops the second process.
  2. The second process launches the logic.

This is an example below :

// Firestore Trigger to monitor document changes
exports.monitorDocument = functions.firestore
    .document('myCollection/myDocument')
    .onUpdate((change, context) => {
        // Check the updated document status
        const newValue = change.after.data();
        const oldValue = change.before.data();

        if (newValue.status !== oldValue.status) {
            console.log('Document status changed');
            // My logic
        }
    });

// Trigger to start the routine and manage the flow
exports.startRoutine = functions.https.onRequest(async (req, res) => {
    const docRef = admin.firestore().collection('myCollection').doc('myDocument');

    // Routine
    try {
        const doc = await docRef.get();
        if (doc.exists && doc.data().status === 'active') {

            // My logic

            // After the routine, check the document again before moving to 'Execution'
            const updatedDoc = await docRef.get();
            if (updatedDoc.data().status === 'active') {
                console.log('Proceeding to execution');
                // Next logic
            } else {
                console.log('Status changed, halting execution');
            }
        }
    } catch (error) {
        console.log('Error:', error);
    }

    res.send('Process completed');
});

Any insights or examples of using another logic, Firestore triggers, or other Google Cloud services to manage such workflows would be greatly appreciated.


Solution

  • [ANSWER] I found a way.

    I create a function subscribeToDocument().

    let yourObject = {};
    const unsubscribe = await subscribeToDocument(myDocumentId, yourObject);
    

    Then in the subscribeToDocument(), you will return a Promise, where there is a subscription to your document snapshot in it. You will pass the object with it, which you will use in your code to have real-time updates even during the execution of a loop.

    async function subscribeToDocument(myDocumentId, yourObject) {
      const docRef = db.collection('your-collection name').doc('myDocumentId');
    
      return new Promise((resolve, reject) => {
        const unsubscribe = docRef.onSnapshot((docSnapshot) => {
          if (docSnapshot.exists) {
            const data = docSnapshot.data();
            Object.assign(yourObject, data);
            resolve(unsubscribe);
          } else {
            reject(new Error("your error");
          }
        }, (error) => {
          unsubscribe();
          reject(error);
        });
      });
    }
    

    With this code, you will have real time update of your document during your program execution.

    Don't forget to unsubscribe(); when you finish the execution.