谷歌云发布/订阅功能在查询 Firestore 时给出“请求的快照版本太旧”

Posted

技术标签:

【中文标题】谷歌云发布/订阅功能在查询 Firestore 时给出“请求的快照版本太旧”【英文标题】:Google cloud pub/sub function gives "The requested snapshot version is too old" when querying firestore 【发布时间】:2021-02-19 01:36:42 【问题描述】:

我有一个对集合执行简单查询的 gcloud pub/sub 函数。它在 10 月 8 日之前运行良好。现在我看到“请求的快照版本太旧”错误消息。

我用相同的代码创建了一个 HTTP 函数并手动运行它,它工作得非常好。

函数如下:

// 0 3 * * * - at 03:00 AM every day
exports.GenerateRankings = functions.pubsub.schedule('0 3 * * *')
    .onRun((context) => 

        console.log("GenerateRankings Task started")

        const playersCollection = admin.firestore().collection('players')

        playersCollection.orderBy("Coin", "desc").get()
            .then((qs) => 
                console.log("Fetching Players by Coin")
                // some staff
                return true
            )
            .catch((error) => 
                console.error("Error fetching players", error)
                return false
            )
    )

这是错误堆栈:

9 FAILED_PRECONDITION: The requested snapshot version is too old.
 at Object.callErrorFromStatus (/workspace/node_modules/@grpc/grpc-js/build/src/call.js:31:26)
 at Object.onReceiveStatus (/workspace/node_modules/@grpc/grpc-js/build/src/client.js:327:49)
 at Object.onReceiveStatus (/workspace/node_modules/@grpc/grpc-js/build/src/client-interceptors.js:305:181)
 at /workspace/node_modules/@grpc/grpc-js/build/src/call-stream.js:124:78
 at processTicksAndRejections (internal/process/task_queues.js:79:11)
 Caused by: Error
 at Query._get (/workspace/node_modules/@google-cloud/firestore/build/src/reference.js:1466:23)
 at Query.get (/workspace/node_modules/@google-cloud/firestore/build/src/reference.js:1455:21)
 at /workspace/index.js:22:47
 at cloudFunction (/workspace/node_modules/firebase-functions/lib/cloud-functions.js:130:23)
 at /layers/google.nodejs.functions-framework/functions-framework/node_modules/@google-cloud/functions-framework/build/src/invoker.js:198:28
 at processTicksAndRejections (internal/process/task_queues.js:97:5) 
    code: 9,
    details: 'The requested snapshot version is too old.',
    metadata: Metadata  internalRepr: Map , options:  
 

我知道还有一个未回答的问题 "The requested snapshot version is too old." error in Firestore 类似于此。我正面临 pub/sub-functions 的这个问题。

感谢您的帮助。

【问题讨论】:

这是在每个函数触发器上发生还是偶发错误? 每次都会出现 我发现这个documentation 引用了这个错误并说if the backlog in the subscription is too old -- and the resulting snapshot would expire in less than 1 hour -- then FAILED_PRECONDITION is returned。不确定它是否有帮助,但这是我找到的唯一一条相关信息。 我会说,您最好使用 Google 的 Issue Tracker 打开一个错误,以便他们能够解决您特定情况下发生的问题。 谢谢,@RafaelLemos。我已经解决了这个问题,请检查我的答案。 【参考方案1】:

如果有人遇到这个问题,我会回答我自己的问题。

经过大量阅读、测试后,我注意到我的日志中有一条警告,例如“函数返回未定义、预期的 Promise 或值”。因为我在函数中返回了一个承诺,所以我没有注意这一点。

在我的函数顶部添加一个 return 修复了我的警告,我的函数已经成功运行了 5 天。

return exports.GenerateRankings = functions.pubsub.schedule('0 3 * * *') ...

【讨论】:

【参考方案2】:

我遇到了同样的问题,在我的情况下,代码如下并返回了这个问题中提到的错误。

const userSnapshots = await this.firestore.collection('Users').where('archive', '==', false).get();
const users = userSnapshots.docs
users.map(async (user) => 
    //code to update user documents
);

然后我将代码更改为以下代码,并且没有返回此问题中提到的错误。

const userSnapshots = await this.firestore.collection('Users').where('archive', '==', false).get();
const users = userSnapshots.docs
const markPromises = users.map(async (user) => 
    //code to update user documents
);

await Promise.all(markPromises);

我不知道这是这个问题的正确答案,但这对我有用。

【讨论】:

这解决了我的部分问题,请参阅我的回复。但经过较长时间后,我仍然会收到错误消息。【参考方案3】:

我花了几个小时试图在“pubsub”中运行一系列操作,然后我决定尝试下面的代码,它成功了。

this.firestore.collection('Users').where('archive', '==', false).get().then(snap=>
    // Code Here
);

【讨论】:

【参考方案4】:

就我而言,我猜问题出在数据的大小以及进行数据管理所花费的时间上。我已将数据拆分为 5000 个元素的部分:

    const store = getFirestore(initializeApp(myConfig));
    const collectionRef = store.collection("users");
    const limit = 5000;
    let docs: Array<QueryDocumentSnapshot<DocumentData>>;
    let querySnapshot: QuerySnapshot<DocumentData>;

    let query = collectionRef.limit(limit);

    do 
        querySnapshot = await query.get();
        docs = querySnapshot.docs; // thanks to @prahack answer
        for (const doc of docs) 
            await manageMyData(doc.id, doc.data());
        
        if (docs.length > 0) 
            // Get the last visible document
            query = collectionRef.startAfter(docs[docs.length - 1]).limit(limit);
        
     while (docs.length > 0);

如果没有我的数据管理,我可以使用 10.000 个元素的一部分(限制 = 10000),但通过管理,我应该减少到 5000 个。

【讨论】:

以上是关于谷歌云发布/订阅功能在查询 Firestore 时给出“请求的快照版本太旧”的主要内容,如果未能解决你的问题,请参考以下文章

谷歌云存储功能在订阅者连接时发送已发送的消息

谷歌云 pubsub node.js 客户端与谷歌云功能不兼容

使用云功能在谷歌云发布/订阅上发布需要 3 分钟 - nodejs

Kubernetes pod 在使用未知证书授权调用谷歌云发布/订阅时失败

谷歌云发布订阅

谷歌云消息“未注册”失败并取消订阅最佳做法?