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

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(使用前将#替换为@)

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

随机推荐

  • 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 支持团队后 他们告诉我我应该使函数幂等 但我不知道如何 因为它是一个可调用函数 更多细节