首页 > 解决方案 > 如果我故意让我的 Google Cloud Functions 出现多个错误,可以吗?

问题描述

我有这样的收藏和子收藏

users/{userID}/followers/{followerID}

每次在关注者子集合中删除关注者文档时,它都会触发下面的这个firestore触发器以减少numberOfFollowers用户文档中的字段。当用户单击取消关注按钮时触发

exports.onDeleteFollower = functions
.firestore.document("users/{userID}/followers/{followerID}")
.onDelete((snapshot, context) => {

     // normally triggered after a user push unfollow button
     // then update the user document 

    const userID = context.params.userID;
    const updatedData = {
        numberOfFollowers: admin.firestore.FieldValue.increment(-1),
    };

    return db.doc(`users/${userID}`).update(updatedData);

});

现在我有这样的情况....

如果用户删除了他们的帐户,那么我将删除用户文档( users/{userID} ),但是如果我删除用户文档,它不会自动删除其子集合中的所有文档,对吧

所以在我删除用户文档后,我有另一个功能可以删除关注者子集合中的所有文档。

但问题是,onDeleteFollower上面的triggers函数会被执行多次,并且会多次抛出错误,因为用户文档已被删除(上面的函数将用于更新已删除用户文档中的字段)

我将在函数模拟器中出现此错误

⚠  functions: Error: 5 NOT_FOUND: no entity to update: app: "myApp"
path <
  Element {
    type: "users"
    name: "u1-HuWQ5hoCQnOAwh0zRQM0nOe96K03"
  }
>

⚠  Your function was killed because it raised an unhandled error.

我实际上可以编写一个逻辑来检查用户文档是否仍然存在。如果存在则更新numberOfFollowers字段

但是如果与用户单击取消关注按钮相比,删除用户文档是非常罕见的,我认为它不是很有效。

我有这样的计划,我会故意让错误发生。说一个用户有1000个follower,那么就会触发onDeleteFollower上面的函数,那么我就会有1000个函数错误

我的问题是......

如果我在短时间内出现多个错误,可以吗?谷歌云功能会终止我的功能,还是......我不知道,我担心会发生我不知道的坏事

据我所知,云函数在被杀死后会自动再次运行该函数,我的函数会在出现这样的错误后再次准备好吗?

我不能让关注者直接从客户端应用程序更新组织者(用户)文档,因为它不安全。创建安全规则来促进这一点很复杂,而且似乎容易出错

标签: node.jsfirebasegoogle-cloud-firestoregoogle-cloud-functions

解决方案


您是否考虑过users/{userID}/followers/{followerID}创建“关注请求”系统而不是直接设置/删除?

"users/{userID}/followRequests/{requestID}": { // requestID would be auto-generated
  user: "{followerID}",
  follow: true // true = add user as follower, false = remove user as follower
}

然后,这允许您使用单个onCreate触发器来更新您的关注者列表,从而无需您的当前onCreateonDelete触发器users/{userID}/followers/{followerID}。通过此功能,您可以对关注其他用户实施限制,例如关注限制或拒绝被阻止用户的关注请求。

export const newFollowRequest = functions.firestore
  .document('users/{userId}/followRequests/{requestId}')
  .onCreate(async (snap, context) => {
    const request = snap.data();
    const followingUserId = request.user;
    const followedUserId = context.params.userId;

    const db = admin.firestore();
    const userDocRef = db.doc(`users/${followedUserId}`);
    const followerDocRef = userDocRef.child(`followers/${followingUserId}`);
    // /users/${followingUserId}/following/${followedUserId} ?
    
    try {
    
      if (request.follow) {
        // Example restriction: Is the user who is attempting to follow
        //                      blocked by followedUserId?
        // await assertUserIDHasNotBlockedUserID(followedUserId, followingUserId);

        // following
        db.update(userDocRef, {
          numberOfFollowers: admin.firestore.FieldValue.increment(1),
        });
        db.set(followerDocRef, {
          /* ... */
        });
      } else {
        // unfollowing
        db.update(userDocRef, {
          numberOfFollowers: admin.firestore.FieldValue.increment(-1),
        });
        db.delete(followerDocRef);
      }
      
      // delete this request when successful
      db.delete(snap.ref);
      
      // commit database changes
      await db.commit();

      console.log(`@${followingUserId} ${request.follow ? "followed" : "unfollowed"} @${followedUserId} successfully`);
      
    } catch (err) {
      // something went wrong, update this document with a failure reason (to show on the client);
      let failureReason = undefined;
      switch (err.message) {
        case "other user is blocked":
          failureReason = "You are blocked by @otherUser";
          break;
        case "user is blocked":
          failureReason = "You have blocked @otherUser";
          break;
      }
      
      return db.ref(snap.ref)
        .update({
          failureReason: failureReason || "Unknown server error";
        })
        .then(() => {
          if (failureReason) {
            console.log("REQUEST REJECTED: " + failureReason);
          } else {
            console.error("UNEXPECTED ERROR:", err)
          }
        },
        (err) => {
          console.error("UNEXPECTED FIRESTORE ERROR:", err);
        });
    }
  });

推荐阅读