Firebase pubsub 函数在模拟器中工作,但在生产中不会立即返回

Posted

技术标签:

【中文标题】Firebase pubsub 函数在模拟器中工作,但在生产中不会立即返回【英文标题】:Firebase pubsub function works in emulator but not returns immediatly in production 【发布时间】:2021-12-17 19:05:20 【问题描述】:

我的预定功能



// 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;
    );
  );

当我从 Cloud Scheduler 手动运行该函数时,它会在 Stripe 调用之前返回 RIGHT

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

我正在记录的日志显示了这一点

如您所见,它在执行 Stripe 调用之前立即返回。

最后一个日志中的错误是这样的:

但是,运行函数、firestore 和 pubsub 模拟器,使用函数 shell 我可以调用 reportUsage 函数,这就是打印出来的内容

谁能告诉我为什么 pubsub 功能在生产环境中不起作用?

【问题讨论】:

【参考方案1】:

您不应在forEach() 循环中使用async/await,请参阅"javascript: async/await with forEach()" 和"Using async/await with a forEach loop"。

你可以使用Promise.all()如下:

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;
  );

【讨论】:

感谢您的回答!但是,我现在遇到了另一个问题,没有详细的日志来解决问题。 Function execution took 4366 ms, finished with status: 'error' 记录后 functions.logger.debug('got SOME_DATA of this user');这可能是因为数据库中的某些数据为NULL,所以我会尝试一下并回复您。 更新:效果很好!非常感谢!!对于将来查看此内容的人,如果有一些 NULL 数据并且您需要跳过 forEach 循环的迭代,return 而不是 continue

以上是关于Firebase pubsub 函数在模拟器中工作,但在生产中不会立即返回的主要内容,如果未能解决你的问题,请参考以下文章

Firebase 模拟器:在函数中使用 PubSub

如何使用 pubsub 模拟器在本地调用 firebase Schedule 函数

如何使用 pubsub 模拟器在本地调用 firebase Schedule 函数

cors 不能在具有 express 的 firebase 功能中工作

与 IBAction 链接的 UIButton 不能在物理设备上的模拟中工作,也不能在 Xcode 9.2 中的模拟器中工作

Firebase 完成回调如何在 Kotlin 中工作