我正在测试如何跟踪和跟踪 Firebase 函数的幂等性,因此我故意使我的函数失败,以便重试要再次传递的事件,并且我能够获得预期的结果,但是我想了解下面提供的一些问题。
我的示例代码:
import { onDocumentWritten } from "firebase-functions/v2/firestore";
import * as logger from "firebase-functions/logger";
import * as admin from 'firebase-admin';
admin.initializeApp();
const db = admin.firestore();
/**
* Checks if an event has already been processed.
*
* @param {string} event_id - The ID of the event to check.
* @returns {Promise<boolean>} - A promise that resolves to true if the event has been processed, false otherwise.
*/
async function CheckForProcessed(event_id: string) {
const docRef = db.collection("processedEvents").doc(event_id);
const snapshot = await db.runTransaction(t => {
return t.get(docRef);
});
return snapshot.exists;
}
/**
* Marks an event as processed.
*
* @param {string} event_id - The ID of the event to mark as processed.
* @returns {Promise<FirebaseFirestore.WriteResult>} - A promise that resolves to the write result.
*/
async function MarkEventProcessed(event_id: string) {
const docRef = db.collection("processedEvents").doc(event_id);
var data =
{
processedAt: admin.firestore.FieldValue.serverTimestamp(),
}
return docRef.set(data);
}
/**
* Idempotency check for firestore events.
*
* @param {any} event - The firestore event data
* @returns {Promise<any>} - A promise that resolves to null or throws an error
*/
export const idempotency_check = onDocumentWritten({
document: "mocks/{mockId}",
retry: true
}, async (event) => {
const eventId = event.id;
logger.info(`Event ID Found : ${eventId}`);
logger.info(`Event Type Found : ${event.type}`);
const mockId = event.params.mockId;
logger.info(`Mock ID Found : ${mockId}`);
const isProcessed = await CheckForProcessed(eventId);
if (isProcessed) {
logger.info('Event already processed:', eventId);
return null;
}
logger.info('Processing event:', eventId);
await MarkEventProcessed(eventId);
const newValue = event.data?.after.exists ? event.data.after.data() : null;
const oldValue = event.data?.before.exists ? event.data.before.data() : null;
logger.info('New Data:', newValue);
logger.info('Old Data:', oldValue);
if (newValue?.name === "Admin") {
logger.debug('Error processing event:', eventId);
throw new Error("Invalid Name");
}
return null;
});
因此,当我尝试创建名称为 Admin 的文档时,它会在云日志记录中记录以下内容:
Event ID Found : b1f66fac-57dc-48bd-99b6-dac11c3e5631
Event Type Found : google.cloud.firestore.document.v1.written
Mock ID Found : 7B6JfVEJFO3hDIDzO8MJ
Processing event: b1f66fac-57dc-48bd-99b6-dac11c3e5631
New Data:
Old Data: null
Error processing event: b1f66fac-57dc-48bd-99b6-dac11c3e5631
Error: Invalid Name at /workspace/lib/index.js:64:15@
2nd Attempt :
Event ID Found : b1f66fac-57dc-48bd-99b6-dac11c3e5631
Event Type Found : google.cloud.firestore.document.v1.written
Mock ID Found : 7B6JfVEJFO3hDIDzO8MJ
Event already processed: b1f66fac-57dc-48bd-99b6-dac11c3e5631
My function setting when deployed :
Timeout : 60 seconds
Minimum instances : 0
Maximum instances : 100
Concurrency : 80
问题:
感谢您提前提供的帮助。
我想知道重试的事件是否将由同一个 Cloud Run 实例处理
系统根本不保证这一点。 它可能会发生,也可能不会发生,您不应该依赖它来有效运作。 只要系统认为合适,服务器实例就可以来来去去。 您的代码应该准备好在任何情况下工作(Cloud Functions 和 Cloud Run 等无服务器产品被称为“无状态”)。
如果重试的事件由同一实例处理,我如何识别?
您必须编写代码来存储和检查实例上的某些全局状态。这完全取决于你自己去弄清楚。系统不会为您提供事件的状态处理。如果您需要检查任何类型的状态,这取决于您。通常,您使用某种数据库或其他独立存储机制来保存可以在任何给定时间运行的任意数量的实例之间共享的状态。
这是测试 Firebase 函数幂等性的方法还是有更好的方法?
严格来说,这是一个观点问题,因此与 Stack Overflow 无关。但是系统或其文档中没有任何内容建议使用任何方式来正式甚至“正确”地测试这一点。