Firebase Functions 偶尔更新文档

Firebase Functions sporadically updating doc

我正在从一家在线商店收到有关创建的类别的 Webhook。以下函数在集合 categories

中创建文档
exports.createProductWebhookCategory = functions
    .https.onRequest(async (request, response) => {
        var category = request.body.product_type;
        try {
            const categoryRef = admin.firestore().collection("categories").doc(`${category}`);
            await categoryRef.set({
                name: category,
            });
            response.status(200).send("Done");
        } catch (error) {
            console.log(error);
            response.status(400).send("Error Cat");
        }
    });

创建类别后,我调用 API 在 Webflow 中创建项目。通过返回的承诺,我得到了我想要存储在之前创建的文档中的项目 ID

我尝试使用 5 个类别(5 个 webhook)进行此操作,5 个类别中只有 1 个或 2 个已更新。其他文档未更新且不包含 webflowId 字段。更新的内容随每次测试而变化 运行。 有人知道我做错了什么吗?

exports.onCreateCategoryCallback = functions
    .runWith({ failurePolicy: true })
    .firestore
    .document("/categories/{categoryId}")
    .onCreate(async (snapshot, context) => {
        const cat = snapshot.data();
        const docId = context.params.categoryId;
        const categoryRef = admin.firestore().collection("categories").doc(docId);
        try {
            const webflow_item = await webflow.createItem({
                collectionId: 'xxx',
                fields: {
                    'name': cat.name,
                    '_archived': false,
                    '_draft': false,
                },
            }, { live: true });
            console.log(`ItemId for Cat ${cat.name} is ${webflow_item._id}`);
            const doc = await categoryRef.get();
            console.log(doc.data());
            const res = await categoryRef.update({
                webflowId: webflow_item._id
            });
            console.log(`RES for ${cat.name} is: `, res);
            console.log("Function complete for cat: ", cat.name);
        } catch (error) {
            console.log(error);
            throw 'error';
        }
    });

更新失败和成功的控制台日志如下

ItemId for Cat Coffee is 620fdc8858462f33735c986

{ name: 'Coffee' } 

RES for Coffee is:  WriteResult { 
_writeTime: Timestamp { _seconds: 1645206666, _nanoseconds: 686306000 } 
} 

Function complete for cat:  Coffee 

问题很可能是因为您没有正确管理第二个 Cloud Function(Firestore 触发的)的生命周期。

正如您将在来自官方 Firebase video series 的关于“JavaScript Promises”的三个视频中看到的那样,您必须 return 一个 Promise 或背景中的一个值在所有情况下触发 Cloud Function异步操作完成。通过这种方式,您可以向 Cloud Function 平台表明它可以关闭您的 Cloud Function 实例 运行,并且您还可以避免在异步操作完成之前关闭此实例。

具体来说,有时会发生您的 Cloud Function 在异步操作完成之前终止的情况,因为您没有 return Promise 或代码末尾的值。其他时候,Cloud Function 平台不会立即终止 Function,异步操作可以完成。您无法控制此行为,因此它表现为不稳定的行为并且很难 understand/debug。

所以以下改编应该可以解决问题(未经测试):

exports.onCreateCategoryCallback = functions
    .runWith({ failurePolicy: true })
    .firestore
    .document("/categories/{categoryId}")
    .onCreate(async (snapshot, context) => {
        const cat = snapshot.data();
        // const docId = context.params.categoryId;
        // const categoryRef = admin.firestore().collection("categories").doc(docId);
        
        // You can replace the two above lines by the following one
        const categoryRef = snapshot.ref; 
        
        try {
            const webflow_item = await webflow.createItem({
                collectionId: 'xxx',
                fields: {
                    'name': cat.name,
                    '_archived': false,
                    '_draft': false,
                },
            }, { live: true });
            console.log(`ItemId for Cat ${cat.name} is ${webflow_item._id}`);
            
            // Not sure why you have the two next lines?? At this stage doc.data() ===  snapshot.data()
            //const doc = await categoryRef.get();
            //console.log(doc.data());
            
            const res = await categoryRef.update({
                webflowId: webflow_item._id
            });
            console.log(`RES for ${cat.name} is: `, res);
            console.log("Function complete for cat: ", cat.name);
            
            return null;  // <== Here return a value when all the asynchronous operations complete
            
        } catch (error) {
            console.log(error);
            return null;
        }
    });

根据上面的评论,创建Category doc时使用Transaction的代码如下(同样我没有测试):

exports.createProductWebhookCategory = functions
    .https.onRequest(async (request, response) => {
        var category = request.body.product_type;
        try {

            const categoryRef = admin.firestore().collection("categories").doc(`${category}`);

            await admin.firestore().runTransaction((transaction) => {

                return transaction.get(categoryRef).then((doc) => {
                    if (!doc.exists) {
                        transaction.set(categoryRef, {
                            name: category,
                        })
                    }
                });
            })
            response.status(200).send("Done");
        } catch (error) {
            console.log(error);
            response.status(400).send("Error Cat");
        }
    });