使用 Cloud Function 在 Firestore 上写入数据突然失败

Posted

技术标签:

【中文标题】使用 Cloud Function 在 Firestore 上写入数据突然失败【英文标题】:Writing data on Firestore sudden fail with Cloud Function 【发布时间】:2020-11-02 08:24:52 【问题描述】:

我在 Cloud Function 中有 5 个预定功能,几个月来一切正常,但今天它突然似乎失败了,或者没有等待 Firestore 完成更新。这是超时还是服务停机?目前所有 5 个预定函数都会调用 updateFunction() 来更新 Firestore 文档中的某些字段,但只是这次更新部分没有成功。

'use-strict'

const functions = require('firebase-functions');
const admin = require('firebase-admin');

admin.initializeApp();
/*
 * 'onCreate' triggered when a document is written to for the first time.
 * 'onDelete' triggered when a document with data is deleted.
 * 'OnWrite' works as 'addValueEventListener' or 'addSnapshotListener' for android.
 * It will fire the function every time there is some item added, removed or changed 
 * from the provided 'database.ref'.
 *
*/
const settingsConfig =  timestampsInSnapshots: true ;

const db = admin.firestore();
db.settings(settingsConfig);


//Message priority must be one of normal or high.
const options =  priority: 'high' ;

exports.schedTask3 = functions.pubsub.schedule('0 11 * * 1')
    .timeZone('Asia/Manila') // Users can choose timezone - default is America/Los_Angeles
    .onRun((context) => 
        //This will be run every Monday at 11:00 AM

        updateFunction();

    );

//THIS FUNCTION IS BEING USE BY 5 SCHEDULE FUNCTION (schedTask1 to schedTask5)
function updateFunction() 

    const dateFormat = require('dateformat');

    dateFormat.i18n = 
        dayNames: [
            'Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat',
            'Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'
        ],
        monthNames: [
            'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec',
            'Januari', 'Februari', 'Maret', 'April', 'Mei', 'Juni', 'Juli', 'Agustus', 'September', 'Oktober', 'November', 'Desember'
        ],
        timeNames: [
            'a', 'p', 'am', 'pm', 'A', 'P', 'AM', 'PM'
        ]
    ;

//SUDDENLY DID NOT REACH THEN RESULT FOR THE FIRST TIME AFTER MONTHS OF WORKING
    return db
        .collection("Lorem")
        .doc("Lorem")
        .set(
            date: dateFormat(new Date().getTime(), "dd mmmm yyyy"),
            value: "Lorem"
        )
        .then(result => 

            const payload = 
                data: 
                    title: "Lorem",
                    description: "Lorem",
                    bigImage: "Lorem",
                    link: "Lorem",
                    environment: "release",
                
            ;

            pushNotif(payload);

            console.log("Updating prediction is success.");

        ).catch(error => 
            return console.error("Failed to send notification.", error);
        )




function pushNotif(payload) 

    return admin.messaging().sendToTopic("Announcement", payload, options)
        .then(val => 
            return console.log("Success!\n" + JSON.stringify(payload), val);
        )
        .catch(error => 
            return console.error("Failed to send notification.", error);
        );


【问题讨论】:

【参考方案1】:

这是因为您错误地管理了 Cloud Function 的生命周期。

在后台调用异步方法的 Cloud Functions 中返回一个 Promise(或一个值)是很重要的,以便告诉 Cloud Functions 平台等到 Promise 被履行或拒绝后再清理函数。详情请参阅https://firebase.google.com/docs/functions/terminate-functions。

在您的情况下,会发生以下情况:有时,Cloud Functions 平台不会立即清理您的 Cloud Function,而 Cloud Functions 可以完成。但在其他情况下,由于您没有返回承诺,Cloud Functions 平台会在完成前对其进行清理。

以下更改(除其他外,请参阅添加几个 returns)应该可以解决问题(未经测试):

'use-strict'

const functions = require('firebase-functions');
const admin = require('firebase-admin');

admin.initializeApp();
/*
 * 'onCreate' triggered when a document is written to for the first time.
 * 'onDelete' triggered when a document with data is deleted.
 * 'OnWrite' works as 'addValueEventListener' or 'addSnapshotListener' for android.
 * It will fire the function every time there is some item added, removed or changed 
 * from the provided 'database.ref'.
 *
*/
const settingsConfig =  timestampsInSnapshots: true ;

const db = admin.firestore();
db.settings(settingsConfig);


//Message priority must be one of normal or high.
const options =  priority: 'high' ;

exports.schedTask3 = functions.pubsub.schedule('0 11 * * 1')
    .timeZone('Asia/Manila') // Users can choose timezone - default is America/Los_Angeles
    .onRun((context) => 
        //This will be run every Monday at 11:00 AM

        return updateFunction()
            .catch(error => 
                console.log(error);
                return null;
            )

    );

//THIS FUNCTION IS BEING USE BY 4 SCHEDULE FUNCTION (schedTask1 to schedTask5)
function updateFunction() 

    const dateFormat = require('dateformat');

    dateFormat.i18n = 
        dayNames: [
            'Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat',
            'Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'
        ],
        monthNames: [
            'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec',
            'Januari', 'Februari', 'Maret', 'April', 'Mei', 'Juni', 'Juli', 'Agustus', 'September', 'Oktober', 'November', 'Desember'
        ],
        timeNames: [
            'a', 'p', 'am', 'pm', 'A', 'P', 'AM', 'PM'
        ]
    ;

    //SUDDENLY DID NOT REACH THEN RESULT FOR THE FIRST TIME AFTER MONTHS OF WORKING
    return db
        .collection("Lorem")
        .doc("Lorem")
        .set(
            date: dateFormat(new Date().getTime(), "dd mmmm yyyy"),
            value: "Lorem"
        )
        .then(result => 

            const payload = 
                data: 
                    title: "Lorem",
                    description: "Lorem",
                    bigImage: "Lorem",
                    link: "Lorem",
                    environment: "release",
                
            ;

            return pushNotif(payload);


        ).catch(error => 
            // throw an error e.g. throw new Error('....'), see https://developer.mozilla.org/en-US/docs/Web/javascript/Reference/Global_Objects/Error
        )




function pushNotif(payload) 

    return admin.messaging().sendToTopic("Announcement", payload, options)
        .then(val => 
            console.log("Success!\n" + JSON.stringify(payload), val);
            return null;
        )
        .catch(error => 
            // throw an error e.g. throw new Error('....'), see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error
        );



我建议您观看 Firebase 视频系列中关于“JavaScript Promises”的 3 个视频:https://firebase.google.com/docs/functions/video-series/。

【讨论】:

就是这样!感谢您突然帮助我理解这些代码出了什么问题。

以上是关于使用 Cloud Function 在 Firestore 上写入数据突然失败的主要内容,如果未能解决你的问题,请参考以下文章

大型集合的 Firestore DeadlineExceeded 异常

如何通过 Cloud Build 访问 GSM 机密并传递给 Cloud Function

使用 Cloud Function 在 Firestore 上写入数据突然失败

在 TypeScript 中为 Firebase Cloud Function 配置 mailgun

在 Cloud Function 的 chrome-drive 中将下载目录设置为 Cloud Storage

如何在 Google Cloud Function 上的 Spring Cloud 函数中获取 Pub/Sub 事件的元数据