【问题标题】:Firebase cloud function doesn't log correctlyFirebase 云功能无法正确记录
【发布时间】:2020-11-19 04:08:01
【问题描述】:

我在每两分钟运行一次的 firebase 函数上运行 pubsub 计划函数。 我尝试记录快照循环收集的事件,但有些事情不正常。

exports.check_event_ended_notification = functions.pubsub.schedule('every 2 minutes').onRun((context) => {
        let default_lineup = "default";
        let events = [];

        return admin.database().ref("Events").once('value')
            .then(snapshot => {
                console.log(("EVENTS number : " + snapshot.numChildren()));
                snapshot.forEach(event_snapshot => {
                    let event_key = event_snapshot.key;
                    let event = event_snapshot.val();
                    events.push(event_key);
                    console.log("EVENT_UID : " + event_key);
                    console.log(("EVENTS : " + events));
                    // iterate through all events and check if they're marked as ended
                    // if not, check if ended
                    let event_status = event[['ended_status']];
                    if (event_status === '0') {
                        // get event date
                        let event_day = event[['date']]['0'];
                        let event_month = event[['date']]['1'];
                        let event_year = event[['date']]['2'];
                        let event_full_date = event_year + "-" + event_month + "-" + event_day;
                        // get today date
                        let today = new Date();
                        let today_day = today.getDate();
                        let today_month = (today.getMonth() + 1);
                        let today_year = today.getFullYear();
                        let today_full_date = today_year + "-" + today_month + "-" + today_day;
                        //create date objects to compare
                        let event_date = new Date(event_full_date);
                        let today_date = new Date(today_full_date);

                        // if event date is in the past
                        // check to see if its marked as ended.
                        if (event_date.getTime() < today_date.getTime()) {
                            console.log("EVENT : past event :  " + event_key);
                            if (event[['ended_status']] === "0") {
                                console.log("EVENT : ended 0  :  " + event_key);
                                //mark as ended
                                // admin.database().ref("Events/"+event_key+"/ended_status").set("1");
                                //create notifications for participation artists
                                for (let artist_key in event[['lineup']]) {
                                    console.log("ARTIST before: " + artist_key);

                                    if (artist_key !== default_lineup) {
                                        console.log("ARTIST after: " + artist_key);

                                        let approved_invitation = event[['lineup']][artist_key]['approved_invitation'];
                                        let handshake_status = event[['lineup']][artist_key]['handshake_status'];
                                        let quit = event[['lineup']][artist_key]['quit'];
                                        let removed = event[['lineup']][artist_key]['removed'];
                                        let event_publish_status = event[['publish_status']];
                                        let owner_uid = event[['owner_uid']];

                                        if (approved_invitation === '1' && handshake_status === '1' && quit === '0' && removed === '0' && event_publish_status === '1') {
                                            return admin.database().ref("Notifications/" + artist_key + "/" + owner_uid + "/" + event['uid']).push({
                                                notification_type: "ended",
                                                seen_status: "0",
                                                timestamp: new Date().getTime()
                                            })
                                        }
                                    }
                                }
                            }
                        }
                    }

                    return null;
                })
            })
    }

虽然开头的 numChildren() 日志显示快照下有 4 个孩子(这是正确的),但 foreach() 方法似乎只运行了两次,收集前两个孩子并将它们添加到“事件”列表。

在此之后日志停止:

2020-07-29T14:22:00.593Z ? check_event_ended_notification: EVENTS number : 4
2020-07-29T14:22:00.593Z ? check_event_ended_notification: EVENT_UID : 3853c2db-f31a-4f46-8c1b-740ca4e3407b
2020-07-29T14:22:00.593Z ? check_event_ended_notification: EVENTS : 3853c2db-f31a-4f46-8c1b-740ca4e3407b
2020-07-29T14:22:00.594Z ? check_event_ended_notification: EVENT_UID : 4253c2db-f31a-4f46-8c1b-740ca4e3407s
2020-07-29T14:22:00.594Z ? check_event_ended_notification: EVENTS : 3853c2db-f31a-4f46-8c1b-740ca4e3407b,4253c2db-f31a-4f46-8c1b-740ca4e3407s

【问题讨论】:

    标签: javascript firebase google-cloud-functions google-cloud-pubsub


    【解决方案1】:

    您没有正确管理 Cloud Function 的生命周期。正如doc 中所述,您需要“通过返回 JavaScript 承诺来解析执行异步处理的函数(也称为“后台函数”)。

    另外,在一个云函数中,不推荐使用on()方法,它设置了一个监听器,而是once()一个,它“只监听一个指定事件类型的事件,然后停止听。”。

    所以以下应该可以解决问题:

    exports.check_event_ended_notification = functions.pubsub.schedule('every 2 minutes').onRun((context) => {
        let default_lineup = "default";
        let events = [];
    
        return admin.database().ref("Events").once('value')  // Note the return here
            .then(snapshot => {
    
                snapshot.forEach(event_snapshot => {
                    let event_key = event_snapshot.key;
                    let event = event_snapshot.val();
                    events.push(event_key)
                    console.log("EVENT_UID : " + event_key);
                    console.log(("EVENTS : " + events));
                });
                
                // Do something with events... We don't have enough details
                
                return null;  // Or return a promise
    
            });
    
    });
    

    根据您的评论更新

    如果你想在forEach()中写入数据库(这是一个异步过程),你应该使用Promise.all(),以便在所有并行调用异步push()时返回一个promise方法完成。

    这里是代码的框架,你应该适应所有的细节:

    exports.check_event_ended_notification = functions.pubsub.schedule('every 2 minutes').onRun((context) => {
        let default_lineup = "default";
        let events = [];
    
        return admin.database().ref("Events/").once('value')
            .then(snapshot => {
    
                const promises = [];
    
                snapShot.forEach(event_snapshot => {
                    let event_key = event_snapshot.key;
                    let event = event_snapshot.val();
                    events.push(event_key)
                    console.log("EVENT_UID : " + event_key);
                    console.log(("EVENTS : " + events));
    
                    promises.push(
    
                        admin.database().ref("Notifications/" + artist_key + "/" + owner_uid + "/" + event['uid']).push({
                            notification_type: "ended",
                            seen_status: "0",
                            timestamp: new Date().getTime()
                        })
    
                    );
    
                });
        
                return Promise.all(promises);   // This returns a promise!!
    
            });
    
    });
    

    【讨论】:

    • 最后的'return null'是否应该出现在forEach循环的末尾或之后?
    • 我使用了return null;,因为我不知道你真正想用events 数组做什么。如果在forEach() 之后调用异步方法(例如将events 数组写入另一个数据库节点),则需要返回此方法返回的承诺。为了更准确地了解正确管理 Cloud Function 生命周期的重要性,我建议您观看 Firebase 视频系列中有关“JavaScript Promises”的 3 个视频:firebase.google.com/docs/functions/video-series
    • 感谢您的推荐,这是我的第一个 js 项目,所以我可能应该学习更多。此外,我使用包含您的建议的完整代码编辑了帖子。
    • 我已经用代码框架更新了答案,您应该适应所有细节。另外,看看我在之前评论中提到的最后一个视频,它涵盖了Promise.all()的使用
    • 是的,我看到了视频,我解决了。非常感谢大家的帮助。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-05-18
    • 2020-02-15
    • 2017-08-08
    • 1970-01-01
    • 2018-08-09
    • 2021-11-17
    相关资源
    最近更新 更多