【问题标题】:Firebase Cloud Function occassionally doesn't executeFirebase 云功能偶尔不执行
【发布时间】:2022-01-19 16:07:11
【问题描述】:

我有一个管理用户预订的 Firestore 项目,并包含下面设置为每天午夜运行的云功能。该函数识别重复预订的标志,并为下周的同一时间/同一天创建一个新的预订(firestore 文档)。

此函数每周可能运行 5 或 6 天,但随机不运行某些天。之所以调用它,是因为我看到“已开始每日定期预订...”日志,但没有创建新文档。

如果我随后更改 pubsub 时间表上的时间,让它在它工作的那天晚些时候再次运行......

日志中没有错误...

努力理解为什么该函数在某些情况下似乎被杀死了......


// Scheduled function to create repeat bookings each day.
exports.createRecurringBooking = functions.pubsub
    .schedule('01 00 * * *')
    .timeZone('Europe/London') // Runs in London Timezone
    .onRun((context) => {
        const firestore = admin.firestore;
        const db = admin.firestore();

        console.log('⏰ Daily Recurring Bookings Started....');


        // Define current day and next day with 00:00 start Time

        const today = new Date(new Date().setHours(0, 0, 0, 0));
        const todayUnix = dayjs(today).valueOf();
        const tomorrowUnix = dayjs(today).add(1, 'day').valueOf();
        const todayTimestamp = firestore.Timestamp.fromMillis(todayUnix);
        const tomorrowTimestamp = firestore.Timestamp.fromMillis(tomorrowUnix);


        // Get bookings from firestore for current day with no end date

        db.collection('bookings')
            .where('startTime', '>=', todayTimestamp)
            .where('startTime', '<', tomorrowTimestamp)
            .where('isRecurring', '==', true)
            .where('recurringCount', '==', -1)
            .get()
            .then((querySnapshot) => {
                querySnapshot.forEach((doc) => {

                    const startTime = dayjs(doc.data().startTime.toDate());
                    const newStartTime = dayjs(startTime).add(7, 'day');
                    const newStartTimeTimestamp = firestore.Timestamp.fromMillis(
                        dayjs(newStartTime).valueOf()
                    );

                    newRecurringBooking = {
                        bookingDetails: doc.data().bookingDetails,
                        channel: doc.data().channel,
                        createdAt: firestore.Timestamp.now(),
                        isRecurring: true,
                        start: doc.data().start ? doc.data().start : newStartTimeTimestamp,
                        location: doc.data().location,
                        recurringCount: doc.data().recurringCount,
                        recurringDescription: doc.data().recurringDescription
                            ? doc.data().recurringDescription
                            : '',
                        recurringWeek: doc.data().recurringWeek + 1,
                        startTime: newStartTimeTimestamp,
                        status: 'confirmed',
                        studio: doc.data().studio,
                        user: doc.data().user,
                    };

                    db.collection('bookings')
                        .doc()
                        .set(newRecurringBooking)
                        .then(() => {
                            console.log(' ⭐ Recurring Booking created! ');
                        })
                        .catch((error) => {
                            console.error('Error Creating Booking: ', error);
                        });
                });
            })
            .catch((error) => {
                console.log(
                    `❌ ERROR when creating open ended recurring bookings! Error: ${error}`
                );
            });


        // Get bookings from firestore for current day with end date

        db.collection('bookings')
            .where('startTime', '>=', todayTimestamp)
            .where('startTime', '<', tomorrowTimestamp)
            .where('isRecurring', '==', true)
            .get()
            .then((querySnapshot) => {
                querySnapshot.forEach((doc) => {

                    const startTime = dayjs(doc.data().startTime.toDate());
                    const newStartTime = dayjs(startTime).add(7, 'day');
                    const newStartTimeTimestamp = firestore.Timestamp.fromMillis(
                        dayjs(newStartTime).valueOf()
                    );

                    // Only create new booking if sequence hasn't ended.
                    if (
                        doc.data().recurringWeek < doc.data().recurringCount &&
                        doc.data().recurringCount > 0
                    ) {
                        
                        newRecurringBooking = {
                            bookingDetails: doc.data().bookingDetails,
                            channel: doc.data().channel,
                            createdAt: firestore.Timestamp.now(),
                            isRecurring: true,
                            location: doc.data().location,
                            recurringCount: doc.data().recurringCount,
                            recurringDescription: doc.data().recurringDescription
                                ? doc.data().recurringDescription
                                : '',
                            recurringWeek: doc.data().recurringWeek + 1,
                            startTime: newStartTimeTimestamp,
                            status: 'confirmed',
                            studio: doc.data().studio,
                            user: doc.data().user,
                        };

                        db.collection('bookings')
                            .doc()
                            .set(newRecurringBooking)
                            .then(() => {
                                console.log(' ⭐  Booking created! ');
                            })
                            .catch((error) => {
                                console.error('Error Creating Booking: ', error);
                            });
                    }
                });
            })
            .catch((error) => {
                console.log(
                    `❌ ERROR when creating recurring bookings with end date! Error: ${error}`
                );
            });

        
        return null;
    });

【问题讨论】:

  • 从您的代码中,仅当 querySnapshot 内部实际上包含文档时才会创建新文档。也许查询没有找到任何与您的参数匹配的文档?除此之外,我不确定 forEach 是否真的在等待您的承诺完成。你应该使用for...ofstackoverflow.com/questions/53892863/…
  • 嘿奥利。你在这方面有什么进展吗?我试图在下面提供答案。你有没有机会检查一下,这有意义吗?如果我的回答有用,请点击它左侧的点赞按钮 (▲)。如果它回答了您的问题,请单击复选标记 (✓) 接受它。这样其他人就知道你已经(充分)得到了帮助

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


【解决方案1】:

您根本没有考虑您在 Cloud Function 中调用的 Firebase 方法的异步特性。我不知道这是否是您问题的确切原因,但它总有一天会以一种难以调试的方式产生问题,因为正如您在问题中解释的那样,它会以一种不稳定的方式出现。

正如您将在来自official Firebase video series 的有关“JavaScript Promises”的三个视频中看到的那样,您必须在后台触发 Cloud Function 中返回 Promise 或值,以向平台指示 Cloud Function 已完成。由于您没有返回 Promise,因此您会遇到这种不一致的行为。有时 Cloud Function 在写入 Firestore 之前被平台杀死,有时 Cloud Function 平台不会立即终止 Function,异步操作可以完成。

您需要使用 async/await 或 Promise.all() 调整您的代码。如果您想在初始化下一个 Promise 之前等待每个 Promise 解决,您可以通过在 async 函数中等待每个 Promise 来做到这一点。如果您不想等待每个 Promise 完成后再开始下一个 Promise,您可以在所有 Promise 都解决后使用 Promise.all() 运行某些东西。

【讨论】:

    猜你喜欢
    • 2017-11-12
    • 2019-12-23
    • 2018-11-07
    • 2019-07-14
    • 2018-06-15
    • 2021-10-26
    • 1970-01-01
    • 2020-04-02
    • 1970-01-01
    相关资源
    最近更新 更多