【问题标题】:What happens to async calls in completed firebase functions?已完成的 firebase 函数中的异步调用会发生什么?
【发布时间】:2020-11-24 14:05:35
【问题描述】:

如果我选择不在 firebase 函数内等待异步调用完成,那么当函数完成时异步调用会发生什么情况?它在哪个线程上继续,它是否仍然在函数的 runtimeOpts 内运行,这对使用有何影响?

import * as firebase from 'firebase';
import * as functions from 'firebase-functions';
import * as admin from 'firebase-admin';

exports.action = functions.https.onRequest((req, res) => {
    admin.database().ref('action').add({ 1: 2 });
    res.end(); // or just `return;` for other functions
});

甚至可能

exports.action2 = functions.https.onRequest((req, res) => {
    new Promise(resolve => setTimeout(() => admin.database().ref('action').add({ 1: 2 })}, 10_000));
    res.end();
});

【问题讨论】:

    标签: firebase google-cloud-functions


    【解决方案1】:

    查看 Cloud Functions 文档中的 section,它解释了为什么“管理函数的生命周期以确保其正确解析很重要”。

    如果您想确保“在您的 CF 成功达到其终止条件或状态之前,运行您的 Cloud Function (CF) 的 Cloud Functions 实例不会关闭”(在您的情况下,当异步工作完成时),你需要“通过返回一个 JavaScript 承诺来解决你的 CF”。

    因此,如果您不这样做,运行 CF 的 Cloud Functions 实例可能会在您对一个或多个异步函数的调用完成之前关闭。

    但是,它确实意味着这种情况总会发生。在您将响应发送回客户端(使用res.end();)后,运行 CF 的 Cloud Functions 实例很可能会继续运行,从而导致异步工作完成。

    问题在于这完全超出了您的控制范围(这取决于 Cloud Functions 平台如何管理您的 Cloud Functions 实例):有时它可能会继续运行(完成异步工作),有时它可能会继续运行(完成异步工作),有时它可能不会。

    您会在 Stack Overflow 上的 Cloud Functions 上找到很多问题,这些问题解释了他们的问题是 Cloud Function 有时会正确执行异步工作,有时则不能:原因很简单,因为它们没有返回由返回的 Promise异步调用。

    这会影响使用吗?

    是的,正如文档中明确指出的那样:“通过正确终止函数,您可以避免因运行时间过长或无限循环的函数而产生过多的费用。”


    因此,具体而言,在您的情况下,您应该执行以下操作:

    exports.action = functions.https.onRequest(async (req, res) => {  //  <-- Note the async keyword here
        await admin.database().ref('action').add({ 1: 2 });
        res.end(); // or just `return;` for other functions
    });
    

    请注意,如果您的 Cloud Function 是 同步(它不调用任何异步方法),您必须使用简单的 return; 语句(或通过调用 send()redirect() ,或 end() 用于 HTTPS 云功能)。例如:

    exports.action = functions.https.onRequest((req, res) => {
        const result = 1 + 3;
        res.status(200).send(result);
    });
    

    exports.unusefulCloudFunction = functions.firestore
      .document('users/{userId}').onWrite((change, context) => {
        const result = 1 + 3;
        console.log(result);
        return;
      });
    

    【讨论】:

    • 所以如果一个函数返回一个 Promise 函数运行器会确保继续运行直到 promise 被解决?你的回答很有见地。我想这意味着如果您并行运行多个异步调用,则需要等待返回值或返回Promise.all,以便在完成调用时没有任何运行。这也意味着我不能真正快速地向用户返回值,即使他们不依赖于慢速异步调用的结果。
    • 是的,您是对的:如果您正确地设法返回异步操作返回的不同 Promise,您可以确定运行您的函数的 Cloud Functions 实例将不会关闭在您的函数成功达到其终止条件或状态之前关闭。如果“您正在并行运行多个异步调用”,您确实必须使用Promise.all。如果异步操作是顺序的(例如:我读取数据库并使用返回的值来读取另一个文档),您需要使用 then() 链接 Promises。
    • “这也意味着我不能真正快速地向用户返回一个值,即使他们不依赖于慢速异步调用的结果”-> 如果没有异步工作在您的函数中执行,您可以在 CF 完成同步工作后立即返回。文档说“使用 return; 语句终止 同步 函数。”
    • @RenaudTarnec 请非常小心functions.https.onRequest,因为它是唯一返回void 的云函数处理程序,这意味着它不会等待Promise——即使是那些使用async/await 语法的。 source
    • @RenaudTarnec 这主要是一个建议的改进,因为您的回答大量讨论了 Promises(非常棒)但是,由于在您的回答正文中遗漏了关于 onRequest 的重要警告,因此第二段具有误导性,具体问题中的示例。书面文档清楚地表明,为 onRequest 返回 Promise 不会使函数保持活动状态,我为可能从 Google 获得这里的未来读者附和。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-10-29
    • 2013-07-04
    • 2021-05-25
    • 2016-09-06
    • 2019-12-04
    • 1970-01-01
    • 2014-11-07
    相关资源
    最近更新 更多