Home > Blockchain >  Firebase pubsub function works in emulator but not returns immediatly in production
Firebase pubsub function works in emulator but not returns immediatly in production

Time:11-04

My scheduled function



// TODO;
export const reportUsage =
  fun.pubsub.schedule("0 0 1 * *").onRun(async (context) => {
    functions.logger.debug("Initialising db");
    const db = admin.firestore();
    const users = await db.collection("users").get();
    users.docs.forEach( async (doc) => {
      functions.logger.debug("Got list of users. Looping..");
      const userData = doc.data();
      const SOME_DATA:number = userData["SOME_DATA"];
      functions.logger.debug("got SOME_DATA of this user");
      const SOME_DATAIntPart:number =
       parseInt(SOME_DATA.toFixed(20).split(".")[0]);
      const SOME_DATAFloatPart:number =
       parseFloat("0."   SOME_DATA.toFixed(20).split(".")[1]);
      const subItemId =
       userData["stripeInfo"]["subscription"]["items"]["data"][0]["id"];
      functions.logger.debug("got sub id of this user");
      await stripe.subscriptionItems.createUsageRecord(subItemId, {
        quantity: SOME_DATAIntPart,
        timestamp: admin.firestore.Timestamp.now().seconds,
      }, {
        timeout: 60,
        maxNetworkRetries: 5,
      });
      functions.logger.debug("got reported to stripe");
      await doc.ref.update({
        "SOME_DATA": SOME_DATAFloatPart,
      });
      functions.logger.debug("updated SOME_DATA");
      return null;
    });
  });

When I run the function manually from Cloud Scheduler, it returns RIGHT before the Stripe call

 await stripe.subscriptionItems.createUsageRecord(subItemId, {
        quantity: SOME_DATAIntPart,
        timestamp: admin.firestore.Timestamp.now().seconds,
      }, {
        timeout: 60,
        maxNetworkRetries: 5,
      });

The logs i'm logging show this Image showing logs in Google Cloud

As you can see, it immediately returns before executing the Stripe call.

The errors in the last log are this: Image showing the error log

However, running the functions, firestore and pubsub emulator, using the functions shell I can call the reportUsage function and this is what prints out

Image showing working logs in emulator

Can someone please tell me why the pubsub function is not working in production?

CodePudding user response:

You should not use async/await within a forEach() loop, see "JavaScript: async/await with forEach()" and "Using async/await with a forEach loop".

You can use Promise.all() as follows:

export const reportUsage = fun.pubsub
  .schedule('0 0 1 * *')
  .onRun(async (context) => {
    functions.logger.debug('Initialising db');

    const db = admin.firestore();
    const users = await db.collection('users').get();

    users.docs.forEach((doc) => {
      functions.logger.debug('Got list of users. Looping..');
      const userData = doc.data();
      const SOME_DATA: number = userData['SOME_DATA'];
      functions.logger.debug('got SOME_DATA of this user');
      const SOME_DATAIntPart: number = parseInt(
        SOME_DATA.toFixed(20).split('.')[0]
      );
      const SOME_DATAFloatPart: number = parseFloat(
        '0.'   SOME_DATA.toFixed(20).split('.')[1]
      );
      const subItemId =
        userData['stripeInfo']['subscription']['items']['data'][0]['id'];
      functions.logger.debug('got sub id of this user');

      const promises = [];
      // We push a Promise to the promsies Array. Note that the then() method returns a promise.
      promises.push(
        stripe.subscriptionItems
          .createUsageRecord(
            subItemId,
            {
              quantity: SOME_DATAIntPart,
              timestamp: admin.firestore.Timestamp.now().seconds,
            },
            {
              timeout: 60,
              maxNetworkRetries: 5,
            }
          )
          .then(() => {
            return doc.ref.update({
              SOME_DATA: SOME_DATAFloatPart,
            });
          })
      );

      functions.logger.debug('updated SOME_DATA');
    });

    await Promise.all(promises);
    return null;
  });
  • Related