我有一个查询 Firestore 的 Google Cloud Function (GCF)。我还有一个用户可以读取/写入 Firestore 的应用程序。在用户使用我的应用程序之前,GCF 工作正常。用户活动几分钟后,GCF 中的查询开始花费很长时间。例如,在 GCF 中,对文档的简单更新将花费 27 秒。
即使用户活动停止几分钟后,GCF 的查询仍然很慢。这是为什么?
代码:
exports.processDocument = functions
.runWith({ timeoutSeconds: 120 })
.https.onRequest(async (req, res) => {
const { documentId } = req.body;
const id = req.body.documentId;
if (!documentId) {
return res.status(400).send("Missing documentId");
}
// Send a 200 response immediately
res.status(200).send("Processing document...");
const db = admin.firestore();
const oneMindDocRef = db.collection("OneMind").doc(documentId);
console.log(id, `Setting ${oneMindDocRef.id} document to being processed.`);
await oneMindDocRef.update({
processing: true,
votingUsers: [],
});
console.log(id, `Set ${oneMindDocRef.id} document to being processed.`);
const oneMindDoc = await oneMindDocRef.get();
console.log(id, "Got OneMind document data");
const activeUsers = oneMindDoc.data().activeUsers;
const roundNumber = oneMindDoc.data().roundNumber;
console.log(id, "Got activeUsers and roundNumber");
if (!activeUsers || activeUsers.length === 0) {
console.log(
id,
`No active users. Resetting ${oneMindDocRef.id} document.`
);
await oneMindDocRef.update({
lastUpdated: admin.firestore.FieldValue.serverTimestamp(),
processing: false,
activeUsersCount: 0,
activeUsers: [],
});
console.log(id, `${oneMindDocRef.id} document reset.`);
console.log(`Document ${oneMindDocRef.id} reset due to no active users.`);
return;
}
const proposedMessagesRef = db.collection("proposedMessages");
if (oneMindDoc.data().userFeedbackMechanism == "slider") {
await calculateWeightedAverageScores(db, documentId);
}
const proposedMessagesDocs = await proposedMessagesRef
.where("roundNumber", "==", roundNumber)
.where("chatroomName", "==", oneMindDoc.data().chatroomName)
.orderBy("votes", "desc")
.orderBy("creation", "asc")
.get();
console.log(id, "Got all proposed messages for the current round.");
if (proposedMessagesDocs.docs.length === 0) {
await oneMindDocRef.update({
activeUsers: [],
activeUsersCount: 0,
lastUpdated: admin.firestore.FieldValue.serverTimestamp(),
processing: false,
});
console.log(
id,
`${oneMindDocRef.id} document reset due to no proposed messages.`
);
console.log(
`Document ${oneMindDocRef.id} reset due to no proposed messages.`
);
return;
}
const highestVotedMessageDoc = proposedMessagesDocs.docs[0];
const highestVotedMessageData = highestVotedMessageDoc.data();
console.log(id, 'Adding winning message to "messages" collection');
const {
message,
creation,
translatedText,
creator,
imageUrl,
chatroomName,
speaker,
} = highestVotedMessageData;
const messageRef = db.collection("messages").doc();
const messageData = {
creation: creation,
creator: creator,
speaker: speaker,
roundNumber: roundNumber,
};
console.log("New message doc id: ", messageRef.id);
if (imageUrl) {
messageData.imageUrl = imageUrl;
}
if (message) {
messageData.message = message;
}
if (translatedText) {
messageData.translatedText = translatedText;
}
if (chatroomName) {
messageData.chatroomName = chatroomName;
}
await messageRef.set(messageData);
console.log(id, "New document created in messages collection.");
let newCurrentSpeaker = oneMindDoc.data().currentSpeaker;
if (oneMindDoc.data().chatroomName !== "OneMind") {
newCurrentSpeaker =
newCurrentSpeaker === oneMindDoc.data().team1
? oneMindDoc.data().team2
: oneMindDoc.data().team1;
console.log(
`Updating current speaker from ${
oneMindDoc.data().currentSpeaker
} to ${newCurrentSpeaker}`
);
}
console.log(id, `Resetting ${oneMindDocRef.id} document for next message`);
await oneMindDocRef.update({
activeUsers: [],
activeUsersCount: 0,
lastUpdated: admin.firestore.FieldValue.serverTimestamp(),
processing: false,
currentSpeaker: newCurrentSpeaker,
roundNumber: admin.firestore.FieldValue.increment(1),
});
console.log(id, `${oneMindDocRef.id} document reset.`);
});
日志:
2024-10-10 18:31:05.099 EDT processDocument4873x1mfdaij Function execution started
2024-10-10 18:31:05.256 EDT processDocument4873x1mfdaij about to start waiting
2024-10-10 18:31:05.257 EDT processDocument4873x1mfdaij done waiting
2024-10-10 18:31:05.257 EDT processDocument4873x1mfdaij Function execution took 157 ms, finished with status code: 200
2024-10-10 18:31:05.257 EDT processDocument4873x1mfdaij OneMind Setting OneMind document to being processed.
2024-10-10 18:31:07.955 EDT processDocument4873x1mfdaij OneMind Set OneMind document to being processed.
2024-10-10 18:31:34.255 EDT processDocument4873x1mfdaij OneMind Got OneMind document data
2024-10-10 18:31:41.855 EDT processDocument4873x1mfdaij OneMind Got activeUsers and roundNumber
2024-10-10 18:31:41.855 EDT processDocument4873x1mfdaij OneMind No active users. Resetting OneMind document.
2024-10-10 18:31:51.860 EDT processDocument4873x1mfdaij OneMind OneMind document reset.
2024-10-10 18:31:51.860 EDT processDocument4873x1mfdaij Document OneMind reset due to no active users.
请注意最后两行代码相隔 27 秒,但其间发生的只是我更新了 Firestore 中的文档。
问题是您在所有工作完成之前发送响应。 Cloud Functions 不支持在响应完成后执行“后台”工作。 发送响应有效终止该功能:
通过正确终止函数,您可以避免运行时间过长或无限循环的函数产生过多费用。此外,您还可以确保在您的函数成功达到其终止条件或状态之前,运行您的函数的 Cloud Functions 实例不会关闭。
使用 res.redirect()、res.send() 或 res.end() 终止 HTTP 函数。
事实上,您可以预期,在发送响应之前未完成的任何“悬空”工作都会表现得不稳定或根本不表现。
为了正确实现此功能,您应该等待所有工作完成后再发送最终响应。