如何使可调用的谷歌云函数幂等

2023-12-03

我有一个谷歌云功能,可以向 firebase 主题发送通知。 该功能一直工作正常,直到突然,它开始同时发送多个通知 2 或 3。联系 Firebase 支持团队后,他们告诉我我应该使函数幂等,但我不知道如何,因为它是一个可调用函数。 更多细节,这是一个参考问题,包含有关该案例的更多详细信息。 下面是该函数的代码。

  • UPDATE 2

这是 admin sdk 中的一个错误,他们在上一个版本中解决了它。

UPDATE

该函数已经是幂等的因为它是一个事件驱动函数 上面的链接包含函数 log as prof 它只运行一次。 经过 2 个月的往返后,它出现了firebase admin sdk 的问题功能代码getMessaging().sendToTopic()重试 4 次,原始请求重试 5 次,然后抛出错误并终止函数。因此,重复通知的原因是管理 SDK 有时由于某种原因无法到达 FCM 服务器。它尝试向所有订阅者发送通知,但在中途或发送所有通知之前,它会收到错误,因此它会从一开始,一些用户收到一个通知,一些用户收到 2、3、4 个通知。 现在的问题是如何防止这些默认重试,或者如何使重试从出现错误的地方继续。可能我会问一个单独的问题。 现在我做了一个简单的解决方案,防止来自接收者(移动客户端)的重复通知。如果一分钟内收到多个具有相同内容的通知,则仅显示一个。

const functions = require("firebase-functions");

// The Firebase Admin SDK to access Firestore.
const admin = require("firebase-admin");
const {getMessaging} = require("firebase-admin/messaging");
const serviceAccount = require("./serviceAccountKey.json");

admin.initializeApp({
  credential: admin.credential.cert(serviceAccount),
  databaseURL: "https://mylinktodatabase.firebaseio.com",
});

exports.callNotification = functions.https.onCall( (data) => {
  // Grab the text parameter.
  const indicator = data.indicator;
  const mTitle = data.title;
  const mBody = data.body;
  // topic to send to
  const topic = "mytopic";
  const options = {
    "priority": "high",
    "timeToLive": 3600,
  };
  let message;
  if (indicator != null ) {
    message = {
      data: {
        ind: indicator,
      },
    };
  } else {
    message = {
      data: {
        title: mTitle,
        body: mBody,
      },
    };
  }

  // Send a message to devices subscribed to the provided topic.
  return getMessaging().sendToTopic(topic, message, options)
      .then(() => {
        if (indicator != null ) {
          console.log("Successfully sent message");
          return {
            result: "Successfully sent message", status: 200};
        } else {
          console.log("Successfully sent custom");
          return {
            result: "Successfully sent custom", status: 200};
        }
      })
      .catch((error) => {
        if (indicator != null ) {
          console.log("Error sending message:", error);
          return {result: `Error sending message: ${error}`, status: 500};
        } else {
          console.log("Error sending custom:", error);
          return {result: `Error sending custom: ${error}`, status: 500};
        }
      });
});

在这个博客中Cloud Functions 专业提示:构建幂等函数,展示了如何使用两种方法实现函数幂等:

使用您的事件 ID

One way to fix this is to use the event ID, a number that uniquely identifies an event that triggers a background function, and— this is important—remains unchanged across function retries for the same event. 4.png

要使用事件 ID 来解决重复问题,首先要从通过以下方式访问的事件上下文中提取它:功能参数。然后,我们利用事件 ID 作为文档 ID,并将文档内容写入 Cloud Firestore。这样,重试的函数执行不会创建新文档,只是用相同的内容覆盖现有文档。同样,一些外部 API(例如,Stripe) 接受幂等密钥以防止数据或工作重复。如果您依赖此类 API,只需提供事件 ID 作为您的幂等性密钥即可。

重试新租约

虽然这种方法消除了函数重试时的绝大多数重复调用,但并行运行的两个重试执行可能多次执行关键部分的可能性很小。为了消除这个问题,您可以使用租用机制,它允许您在特定的时间内独占执行函数的非幂等部分。在此示例中,第一次执行尝试获得租约,但第二次尝试被拒绝,因为第一次尝试仍保留租约。最后,第一次失败后的第三次尝试重新获取租约并成功处理事件。

5.png

要将此方法应用于您的代码,只需在发送电子邮件之前运行 Cloud Firestore 事务,检查事件是否已得到处理,同时还存储当前执行尝试拥有发送电子邮件的独占权利之前的时间。其他并发执行尝试将被拒绝,直到租约到期,从而消除所有意图和目的的所有重复项。

另外,正如另一篇中所述question:

问:是否需要使这些 onCall 函数具有幂等性,或者它们永远不会执行重试?

答:致电onCall函数不会自动重试。由应用程序的客户端和服务器端代码来就重试策略达成一致。

也可以看看:

  • 重试事件驱动函数 - 最佳实践
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何使可调用的谷歌云函数幂等 的相关文章

  • 将 Javascript 对象的属性从 string 更改为 int

    我有一个对象数组 每个对象具有三个属性 年份 总计 人均 例子 0 Object per capita 125 8 total 1007 2 year 2009 这些属性是字符串 我想创建一个循环来遍历数组并将它们转换为 int 我尝试了以
  • Firebase,只得到新的孩子[重复]

    这个问题在这里已经有答案了 var firebase new Firebase firebaseRef on child added function snapshot 这将接收所有元素 有没有办法在创建新的 Firebase 引用时不接收
  • 如何正确清理来自 AngularJS 控制器的无效输入的表单?

    我有一个 AngularJS 表单 其中包含 除其他字段之外 类型之一url 后者很重要 因为这会强制相应的输入成为有效的 URL 在某些条件下 例如 要关闭具有此类表单的模式对话框 我想以编程方式清除该表单 为此 我实现了方法reset基
  • Google Cloud - 谷歌云功能的出口 IP / NAT / 代理

    我正在为我的公司构建一个数据摄取层 其中有很多不同的集成点 其余 api 某些 API 要求您从列入白名单的 IP 进行连接 我真的很想使用谷歌云功能 pubsub 来构建摄取逻辑 因为它具有可扩展性并降低了成本 但问题是谷歌云功能总是从随
  • .push() 将多个对象放入 JavaScript 数组中返回“未定义”

    当我将项目添加到beats数组然后console log用户时 我得到了数组中正确的项目数 但是当我检查 length 时 我总是得到 1 尝试调用索引总是会给我 未定义 如下所示 Tom beats 1 我想我错过了一些明显的东西 但这让
  • 为什么 window 与 Internet Explorer 中的 window.self 不同?

    关于我如何遇到这个问题有一个复杂的背景故事 但为什么self属性不完全等于窗口本身 在 Safari 和 Firefox 及其朋友中 结果如我所料 gt window window self true gt window window se
  • IntersectionObserver是否支持水平滚动观察?

    我制作了几个垂直滚动 IntersectionObserver 模块 但我对水平滚动感兴趣 根将是 div 观察目标将是 img 我想观察当 img 放大但 div 保持视口宽度时的变化 我什至不确定移动 Safari 是否会将缩放后的图片
  • JavaScript 中的 Promise 有什么意义?

    一个承诺是一个 可能现在可用 或将来可用 或永远不可用的值 来源 MDN 假设我有一个想要处理图片的应用程序 图片已加载 例如在算法在后台使用它之后 或某种其他类型的延迟 现在我想检查一下图片是否可以在future 通过使用承诺 而不是回调
  • IE 中的 XPath 查询使用从零开始的索引,但 W3C 规范是从一开始的。我应该如何处理差异?

    问题 我正在转换目前仅适用于 Internet Explorer 的相对较大的 Javascript 代码 以便使其也适用于其他浏览器 由于代码广泛使用 XPath 我们做了一些兼容性功能以使事情变得更容易 function selectN
  • 如何在另一个自定义 Hook 中使用返回值的自定义 Hook?

    我正在使用 React native 其中有一个名为的自定义 HookuseUser使用以下方法从 AWS Amplify 获取用户信息Auth getUserInfro方法 然后获取返回对象的一部分并用它设置一个状态变量 我还有另一个名为
  • mongodb 聚合 - 累积字段的不同组值

    如果我有Player表格文件 name String score Int 我有Group文档 其中组代表玩家列表 groupName String players ObjectID 玩家可以属于多个组 我想做一个聚合Player文档 按以下
  • JavaScript eval("{}") 返回行为?

    根据ECMA 262 规范 http www ecma international org publications files ECMA ST Ecma 262 pdf 以下语句返回1 eval 1 eval 1 eval 1 var a
  • 表单发布请求并存储收到的数据

    我有一个非常简单的表单 在提交时发出发布请求
  • 用于选择特定 div 中具有特定类的锚元素的 jQuery 选择器是什么

    我有一些这样的代码 我想选择每个 a 带有类的标签status在 div 中foo div a class status a div 你可以这样做 foo find status a
  • 使用javascript动态更新css内容

    需要将 css 更新为动态值 我不确定最好的方法是什么 div style zoom 1 div 缩放级别将根据窗口大小调整触发 应用程序将相应缩放 我将此应用程序加载到 cordova 中并让它在 iPAD 中运行 然后我意识到需要使用
  • 使用 Enzyme 测试 `React.createRef` api

    我想测试下面的类 它使用React createRef api 不过 快速搜索并没有发现任何这样做的例子 有人成功过吗 我该如何嘲笑裁判 理想情况下我想使用shallow class Main extends React Component
  • react-native - 图像需要来自 JSON 的本地路径

    你好社区 我正在react native中开发一个测试应用程序 并尝试从本地存储位置获取图像 我实际在做什么 我将图像直接链接源提供给 var 并在渲染函数中调用此方法 react 0 14 8 react native 0 23 1 np
  • 滚动顶部不符合预期

    Note 由于上次忘记奖励而重新开放赏金 A Woff 大师已经给出答案 我想在用户展开某一行时到达该行 这样当最后一个可见行展开时 用户不必向下滚动即可查看内容 I used example tbody on click td green
  • 如何通过索引访问 JSON 对象中的字段

    我知道这不是最好的方法 但我别无选择 我必须通过索引访问 JSONObject 中的项目 访问对象的标准方法是只写this objectName or this objectName 我还找到了一种获取 json 对象内所有字段的方法 fo
  • 测量窗口偏移

    有没有一种方法可以测量 jQuery 中窗口的偏移量 以便我可以比较 固定 元素和相对定位元素的位置 我需要能够知道窗口滚动了多远 以便我可以使用该图来计算固定元素的高度 相对于视口顶部 和相对对象的高度 相对于顶部 之间的差异文件的内容

随机推荐

  • print 函数中的结束逗号有什么用? [复制]

    这个问题在这里已经有答案了 这段代码来自http docs python org 2 tutorial errors html predefined clean up actions with open myfile txt as f fo
  • 我可以仅使用 CSS 为 bootstrap 图标添加颜色吗?

    Twitter 的引导程序使用 Glyphicons 的 Icons 他们是 available in dark gray and white 默认情况下 是否可以使用一些 CSS 技巧来改变图标的 颜色 我希望 css3 能有一些其他的优
  • 给定日期时间的年龄(以年为单位,具有小数精度)

    如何在 C 日期时间中获取给出出生日期的人的年龄 我想要一个精确的年龄 比如 40 69 岁 这将计算出准确的年龄 年龄的小数部分是相对于上一个生日和下一个生日之间的天数来计算的 因此它将正确处理闰年 小数部分在一年中是线性的 并且不考虑月
  • 如何在实体框架中为不同用户使用不同的连接字符串

    我有一个要求 我需要为不同的用户提供不同的连接字符串 我们的想法是拥有username and password在登录屏幕上提供 用作username and password连接字符串的 从而使应用程序为不同的用户使用不同的连接字符串 并
  • sqlite3 c/c++,获取聚合查询涉及的表名

    我在 C 项目中使用 sqlite 我希望能够获取查询中涉及的表名 Ex SELECT FROM Employee 应该返回Employee 现在我使用成功了qlite3 column table name doc 对于此类查询 但对于聚合
  • VB.NET 中令人困惑的逻辑运算符

    我正在使用用 VB 编写的遗留代码库 并且遇到了一个我不理解的条件运算符 并且无法弄清楚要搜索什么来解决它 我正在处理的是以下代码和结果为 true 的变量 我不明白的具体部分是 1 第一个之间的关系X和第一个括号 2 2 的作用X lt
  • jq:传递不带引号的字符串参数

    我想传递一个不带引号的参数 JQ arg 默认情况下有双引号 因为它应该用作过滤器 例如 propt properties final jq r c arg p propt p sample json echo final 样本 json
  • Scala 柯里化与部分应用函数

    我意识到这里有几个问题what柯里化和部分应用函数是 但我问的是它们有何不同 作为一个简单的例子 下面是一个用于查找偶数的柯里化函数 def filter xs List Int p Int gt Boolean List Int if x
  • AS3 - 如何使用鼠标事件的像素/点检测而不是对象检测

    这看起来应该很容易 我都不好意思问 但我就是不明白 我有一个大的圆形 MovieClip 用作按钮 该影片剪辑包含具有透明背景的PNG插入到影片剪辑中 由于其尺寸 四个角 边界框 上有较大的空白注册区域 如何让鼠标注册为仅位于圆形像素上方
  • 我需要在 ASP.Net core Web API 的验证属性中返回自定义的验证结果(响应)

    我需要在 ASP Net core Web API 中返回自定义的验证结果 响应 失效属性 这是我创建的 ValidationAttribute class MaxResultsAttribute ValidationAttribute p
  • 如何单独更改按钮 pygame 上文本的不透明度?

    我下面有以下代码 它是从另一篇文章中获取的按钮的类 我想知道是否可以更改按钮背景的不透明度而不更改其上文本的不透明度 我怎样才能实现这个目标 Code import pygame pygame init font pygame font S
  • 如何读取 zip 存档中的单个文件

    我需要读取 zip 文件内的单个文件 test txt 的内容 整个 zip 文件是一个非常大的文件 2GB 并且包含很多文件 10 000 000 因此提取整个文件对我来说不是一个可行的解决方案 如何读取单个文件 尝试使用zip wrap
  • 使用 css 在 上设置强制宽度,该宽度位于 下,使用 colspan 而不使用 colgroup

    我想设置宽度td in tbody在下面thead th有一个colspan 2 具有硬定义的列宽 以 为单位 如果单元格内容超出 浏览器外壳不会动态调整表格宽度 sample width 100 table layout fixed sa
  • 如何在 CakePHP 2.0 中发送带有附件的电子邮件?

    我正在尝试使用 CakePHP 2 0 发送一封带有附件的电子邮件 该文件由用户通过表单提交 到目前为止我有 App uses CakeEmail Network Email email new CakeEmail email gt att
  • 使用 handler.postDelayed 获取剩余时间

    我在用handler postDelayed为某些动画内容创建一些延迟的方法 像这样 Handler h new Handler h postDelayed new Runnable Override public void run Sta
  • 如何在 foreach 循环中删除 xmlnode?

    在下面的代码中 我使用 foreach 循环来检查节点列表中的每个节点并删除其中的一些节点 删除一个节点后 foreach 循环抛出以下错误 元素列表已更改 枚举操作无法继续 我怎样才能避免它 public static XmlNodeLi
  • 在C中使用紧凑指针寻址二维数组的元素[关闭]

    Closed 这个问题需要调试细节 目前不接受答案 我正在使用 C 实现莫尔斯电码并遇到一些基础知识 基本思想是我有 A 到 Z 的二维字符数组 每个数组的第一个元素是一个字母表 后跟相应的莫尔斯电码 程序将接收一个字符 一旦找到匹配项 该
  • Hadoop 类型与映射预期值中的键不匹配文本收到的值 LongWritable

    有人知道为什么我会收到此错误吗 我看过很多其他类似的帖子 但其中大多数不适用于我 我也尝试了发布的一些确实适用于我的解决方案 但它们不起作用 我确信我只是错过了一些愚蠢的东西 谢谢您的帮助 chris chrisUHadoop usr lo
  • 将按类别分类的行添加到我的数据框中

    我使用 groupby 创建了一个新的聚合数据框 但在每个类别下添加小计行时遇到问题 我尝试过使用 pd groupby 和数据透视表并更改索引 但我无法按照我想要的方式表示数据 为每个 客户 创建 USD Balance 小计 但将其添加
  • 如何使可调用的谷歌云函数幂等

    我有一个谷歌云功能 可以向 firebase 主题发送通知 该功能一直工作正常 直到突然 它开始同时发送多个通知 2 或 3 联系 Firebase 支持团队后 他们告诉我我应该使函数幂等 但我不知道如何 因为它是一个可调用函数 更多细节