Firebase云交易并非总是能完成 [英] Firebase cloud transactions not always finishing

查看:32
本文介绍了Firebase云交易并非总是能完成的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当尝试在子集合中发布新的 review 时,我尝试通过事务更新Firestore数据库中 restaurant 文档的平均评分评论.以下代码适用于评论输入缓慢的情况,但是如果我通过在几秒钟内插入10条评论进行压力测试,它将不再正确更新平均评分(即,它可能仅计算前5条评论,而不会基于休息).我对交易的理解是,当数据在其脚下改变时,它将自动重新运行,以确保正确更新值.

I am attempting to update the average rating of a restaurant document in my Firestore database with a transaction when a new review is posted in the sub-collection reviews. The following code works for when reviews come in slowly but if I run some stress testing by inserting 10 reviews within a few seconds it will no longer update the average rating properly (i.e. it may only count the first 5 reviews and not update based on the rest). My understanding of transactions was that it will re-run automatically when the data has changed beneath its feet to ensure it is properly updating the values.

这是使用的云功能.

exports.reviewCreated = functions.firestore.document('/restaurants/{restaurantid}/reviews/{reviewid}').onCreate((snapshot, context) => {

    const rest_id = context.params.restaurantid;
    const rest_ref = admin.firestore().collection('restaurants').doc(rest_id)
    const rest_rating = snapshot.data().rest_rating;

    console.log('The new rest rating is: ' + rest_rating);
    try {
        admin.firestore().runTransaction((t) => {
            return t.get(rest_ref).then((rest_doc) => {
                const new_total_reviews = rest_doc.data().totalReviews + 1;
                const current_avg_rating = rest_doc.data().averageRating

                const new_avg_rating = current_avg_rating + ((rest_rating - current_avg_rating)/new_total_reviews);
                t.update(rest_ref, {totalReviews: new_total_reviews,
                                averageRating: new_avg_rating});
            });
        })

    } catch (e) {
        console.log('[Review Created] Transaction Failed', e);
        return null;
    }
});

对此进行测试.我的应用程序的调试屏幕上有一个按钮,可以插入假评论,代码如下

To test this. I have a button on a debug screen of my app to insert a fake review, the code is as follows

<Button title = 'Add Review! (Test)' 
    onPress = {() => 
    {
        console.log(this.state.uid);
        var new_uuid = uuid.v4();

        firestore()
        .collection('restaurants')
        .doc(this.state.restid)
        .collection('reviews')
        .doc(new_uuid)
        .set({
            rest_rating: Math.floor(Math.random() * 5) + 1,
            review_name: 'test'
        });
    }}
/>

对于TS来说我还很陌生,所以我会尽力学习绳索,因此观看任何阅读材料/视频也都将有所帮助!:)

I am fairly new to TS and am trying my best to learn the ropes so any readings/videos to watch would also be helpful! :)

推荐答案

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

You are not correctly managing the life cycle of your Cloud Function. As explained in the doc, you need to "resolve functions that perform asynchronous processing (also known as "background functions") by returning a JavaScript promise".

对于您而言,您应该返回 runTransaction返回的Promise() 方法,如下所示:

In your case you should return the Promise returned by the runTransaction() method, as follows:

exports.reviewCreated = functions.firestore.document('/restaurants/{restaurantid}/reviews/{reviewid}').onCreate((snapshot, context) => {

    const rest_id = context.params.restaurantid;
    const rest_ref = admin.firestore().collection('restaurants').doc(rest_id)
    const rest_rating = snapshot.data().rest_rating;

    console.log('The new rest rating is: ' + rest_rating);
    return admin.firestore().runTransaction((t) => {   // !!! See the return here
        return t.get(rest_ref).then((rest_doc) => {
            const new_total_reviews = rest_doc.data().totalReviews + 1;
            const current_avg_rating = rest_doc.data().averageRating

            const new_avg_rating = current_avg_rating + ((rest_rating - current_avg_rating) / new_total_reviews);
            t.update(rest_ref, {
                totalReviews: new_total_reviews,
                averageRating: new_avg_rating
            });
        });
    })
    .catch(e => {
        console.log('[Review Created] Transaction Failed', e);
        return null;
    });
});

通过不正确地管理您的Cloud Function的生命周期,您可能会生成一些不稳定"的错误消息.功能的行为(如您提到的交易并非总是会完成").

By uncorrectly managing the life cycle of your Cloud Function you are potentially generating some "erratic" behavior of the Cloud Function ("transactions not always finish" as you mention).

在后台触发的Cloud Function中返回一个Promise(或一个值),向Cloud Function平台指示它在Promise完成之前不应该终止该功能,并避免在异步操作完成之前终止它.

Returning a Promise (or a value) in a background triggered Cloud Function indicates to the Cloud Function platform that it should not terminate the Function until the Promise has fulfilled and avoids it is terminated before the asynchronous operations are done.

交易未必总是完成"的原因就在于此.可能是以下情况:由于上述原因,有时会在异步事务完成之前终止您的Cloud Function.并且其他时间,Cloud Function平台不会立即终止该功能,并且异步事务可以完成(即可以在Cloud Function终止之前完成).

So the reason why "transactions not always finish" is most probably the following: it happens sometimes that your Cloud Function is terminated before the asynchronous Transaction is completed, for the reason explained above. And the other times, the Cloud Function platform does not terminate the Function immediately and the asynchronous Transaction can be completed (i.e. has the possibility to complete before the Cloud Function is terminated).

这篇关于Firebase云交易并非总是能完成的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆