Firestore transactions getting triggered multiple times resulting in wrong data

南楼画角 提交于 2021-02-17 20:55:15

问题


So I have a cloud function that is triggered each time a transaction is liked/unliked. This function increments/decrements the likesCount. I've used firestore transactions to achieve the same. I think the problem is the Code inside the Transaction block is getting executed multiple times, which may be correct as per the documentation.

But my Likes count are being updated incorrectly at certain times.

 return firestore.runTransaction(function (transaction) {
        return transaction.get(transRef).then(function (transDoc) {
            let currentLikesCount = transDoc.get("likesCount");
            if (event.data && !event.data.previous) {
                newLikesCount = currentLikesCount == 0 || isNaN(currentLikesCount) ? 1 : transDoc.get("likesCount") + 1;
            } else {
                newLikesCount = currentLikesCount == 0 || isNaN(currentLikesCount) ? 0 : transDoc.get("likesCount") - 1;
            }
            transaction.update(transRef, { likesCount: newLikesCount });
        });
    });

Anyone had similar experience


回答1:


Guys finally found out the cause for this unexpected behaviour.

Firestore isn't suitable for maintaining counters if your application is going to be traffic intensive. They have mentioned it in their documentation. The solution they suggest is to use a Distributed counter.

Many realtime apps have documents that act as counters. For example, you might count 'likes' on a post, or 'favorites' of a specific item.

In Cloud Firestore, you can only update a single document about once per second, which might be too low for some high-traffic applications.

https://cloud.google.com/firestore/docs/solutions/counters

I wasn't convinced with that approach as it's too complex for a simple use case, which is when I stumbled across the following blog

https://medium.com/evenbit/on-collision-course-with-cloud-firestore-7af26242bc2d

These guys used a combination of Firestore + Firebase thereby eliminating their weaknesses.

Cloud Firestore is sitting conveniently close to the Firebase Realtime Database, and the two are easily available to use, mix and match within an application. You can freely choose to store data in both places for your project, if that serves your needs.

So, why not use the Realtime database for one of its strengths: to manage fast data streams from distributed clients. Which is the one problem that arises when trying to aggregate and count data in the Firestore.

Its not correct to say that Firestore is an upgrade to the Realtime database (as it is advertised) but a different database with different purposes and both can and should coexist in a large scale application. That's my thought.




回答2:


It might have something to do with what you're returning from the function, as you have

return transaction.get(transRef).then(function (transDoc) { ... })

And then another return inside that callback, but no return inside the inner-most nested callback. So it might not be executing the transaction.update. Try removing the first two return keywords and add one before transaction.update:

firestore.runTransaction(function (transaction) {
        transaction.get(transRef).then(function (transDoc) {
            let currentLikesCount = transDoc.get("likesCount");
            if (event.data && !event.data.previous) {
                newLikesCount = currentLikesCount == 0 || isNaN(currentLikesCount) ? 1 : transDoc.get("likesCount") + 1;
            } else {
                newLikesCount = currentLikesCount == 0 || isNaN(currentLikesCount) ? 0 : transDoc.get("likesCount") - 1;
            }
            return transaction.update(transRef, { likesCount: newLikesCount });
        });
    });



回答3:


Timeouts

First of all, check your Cloud Functions logs to see if you get any timeout messages.

Function execution took 60087 ms, finished with status: 'timeout'

If so, sort out your function so that it returns a Promise.resolve(). And shows

Function execution took 344 ms, finished with status: 'ok'

Idempotency

Secondly, write your data so that the function is idempotent. When your function runs, write a value to the document that you are reading. You can then check if that value exists before running the function again.

See this example for ensuring that functions are only run once.



来源:https://stackoverflow.com/questions/48759969/firestore-transactions-getting-triggered-multiple-times-resulting-in-wrong-data

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!