【发布时间】:2020-04-18 07:06:46
【问题描述】:
背景
据我所知,Firebase 触发的函数可以仅从一个触发事件运行多次(我想我可以从 Firebase 的日志中看到这一点)。
由于这可能是一种数据损坏行为,我想实现一些标志,如果它发现标志是true,它允许函数停止。
在数据库中创建该对象后,我希望这个函数(Typescript)只运行一次。
例如:
adm.database().ref('/Users/{UserID}')
我打算在数据库中为每个用户节点存储一个键值对:
{"alreadyTriggered":true}
或者将'触发器'存储在单独的节点中,没关系。
然后当 Firebase 决定触发相应的函数时,如果不是第一次运行,我将进行检查并停止该函数的执行:
data = snapshot.val();
if (data.alreadyTriggered) {
return;
}
// The function continues here
实施
(有些括号和括号可能会丢失,这是一个在浏览器窗口中编写的伪代码-Typescript)
index.ts:
import * as u from './users';
import * as ff from 'firebase-functions';
import * as adm from 'firebase-admin';
import * as types from './types';
// Triggered function
export const userCreated = ff.database.ref('/Users/{userId}').onCreate((sn, ctx) => {
let user: types.User = sn.val();
console.log(`New user created, User Id: ${ctx.params.userId}`);
return u.onCreated(user);
});
users.ts:
// Function implementation
export function onCreated(user: types.User): Promise<void> {
return adm.database().ref("/Triggers").once('value', snapshot => {
let data: any = snapshot.val();
const alreadyTriggered: boolean = data.alreadyTriggered;
}).then(alreadyTriggered => {
if (alreadyTriggered) {
// We would like to stop any execution here
return
}
else {
console.log(`Continuing processing`)
}
}).then(() => {
// This code should be reached only if alreadyTriggered is set to false
// do actual work with the user object
//...someNewData
//then save it
adm.database().ref('/Users').child(user.userId).update(someNewData)
})
}
问题
问题是我不知道如何可靠地停止执行该函数。我曾尝试使用return(不起作用)、break(仅用于循环),然后我开始使用throw new Error('Stopping function execution'),但它似乎并没有可靠地停止——有时我在日志中看到该函数会继续执行,尽管alreadyTriggered 肯定是true。
问题
如何从其代码中停止执行 Firebase Typescript 函数?
【问题讨论】:
-
请阅读文档中关于idempotence 的部分。您将需要一个实现幂等性的策略,但是有很多方法可以做到这一点,具体取决于您的功能的需要。您在此处显示的信息不足以说明需要什么,或者您尝试过的内容没有按您期望的方式工作。考虑显示不起作用的整个函数,而不仅仅是几行。
-
道格,非常感谢您的评论。我已经阅读了关于幂等性的文档,但是我能找到的关于停止的唯一提示是调用一些我找不到的 Node 回调。我已经按照您的建议提供了整个功能,谢谢!
-
我看过关于幂等性的视频(你提供的链接),谢谢。但是,它描述了一种避免多次运行 _same_instance_of_the_same_function 的策略(通过上下文),但我想确保即使它是对同一函数的不同调用,如果一个调用已经在运行,我也会停止所有其他调用.到目前为止,我能够通过返回
return Promise.reject("Stopping")可靠地阻止它,但我不确定这是一个优雅的解决方案。 -
您必须将一些数据存储在数据库或其他持久性存储中,以便其他调用可以检查以防止函数完成。
-
是的,这就是我使用
/Triggers并检查alreadyTriggered值的原因。但是一旦函数发现它是true- 如何停止函数中其他代码的执行?
标签: javascript typescript firebase firebase-realtime-database google-cloud-functions