谷歌云平台推送订阅发送重复消息 ID 字段

Posted

技术标签:

【中文标题】谷歌云平台推送订阅发送重复消息 ID 字段【英文标题】:Google Cloud Platform push subscription sending duplicate message ID fields 【发布时间】:2021-09-30 02:12:32 【问题描述】:

我们有一个 GCP 发布订阅主题,其中包含指向 Cloud Run 应用的推送订阅。推送订阅正在向我们的 Cloud Run 端点发送以下 json,其中包含重复的 messageId/message_id 字段:


  "message": 
    "attributes": 
      "bucketId": "...",
      "eventTime": "2021-07-22T15:56:45.913174Z",
      "eventType": "OBJECT_FINALIZE",
      "notificationConfig": "...",
      "objectGeneration": "1626969405908262",
      "objectId": "...",
      "payloadFormat": "JSON_API_V1"
    ,
    "data": "...",
    "messageId": "2717017549133308",
    "message_id": "2717017549133308",
    "publishTime": "2021-07-22T15:56:46.081Z",
    "publish_time": "2021-07-22T15:56:46.081Z"
  ,
  "subscription": "projects/.../subscriptions/..."

当我们尝试将此 json 转换为 ReceivedMessage protobuf 对象时出现问题:

import com.google.pubsub.v1.ReceivedMessage;

ReceivedMessage.Builder receivedMessageBuilder = ReceivedMessage.newBuilder();
JsonFormat.parser().merge(json, receivedMessageBuilder);

我在我的 Cloud Run 应用中使用最新版本的 protobuf-java:

    <dependency>
      <groupId>com.google.protobuf</groupId>
      <artifactId>protobuf-java</artifactId>
      <version>3.17.3</version>
    </dependency>

由于 json 是由 GCP 生成的,并且我们正在将 json 转换为 Google 定义的 protobuf 对象,我希望它可以正常工作。但相反,我们收到以下错误:

Caused by: com.google.protobuf.InvalidProtocolBufferException: Field google.pubsub.v1.PubsubMessage.message_id has already been set.
    at com.google.protobuf.util.JsonFormat$ParserImpl.mergeField(JsonFormat.java:1648)
    at com.google.protobuf.util.JsonFormat$ParserImpl.mergeMessage(JsonFormat.java:1500)
    at com.google.protobuf.util.JsonFormat$ParserImpl.merge(JsonFormat.java:1458)
    at com.google.protobuf.util.JsonFormat$ParserImpl.parseFieldValue(JsonFormat.java:1999)
    at com.google.protobuf.util.JsonFormat$ParserImpl.mergeField(JsonFormat.java:1663)
    at com.google.protobuf.util.JsonFormat$ParserImpl.mergeMessage(JsonFormat.java:1500)
    at com.google.protobuf.util.JsonFormat$ParserImpl.merge(JsonFormat.java:1458)
    at com.google.protobuf.util.JsonFormat$ParserImpl.merge(JsonFormat.java:1340)
    at com.google.protobuf.util.JsonFormat$Parser.merge(JsonFormat.java:476)

我在这里做错了吗?如果我手动删除重复的字段(messageIdpublishTime),则消息会按预期转换得很好。但是由于 json 是由 GCP 在内部生成的,所以我在云环境中无法控制它。有人对我如何成功地将这个 json 转换为 com.google.pubsub.v1.ReceivedMessage 有任何建议吗?

【问题讨论】:

【参考方案1】:

不幸的是,JSON 中字段的表示方式发生了变化。原本使用“message_id”和“publish_time”,但为了匹配Protocol Buffer JSON standards,分别改为“publishTime”和“messageId”。为了确保那些依赖旧方式的人的向后兼容性,两者都被写入消息中。多年来,JSON 解析器中对这种情况的支持发生了变化,并且有一个 open issue for protocol buffers 来处理它。目前,唯一的选择是在调用 JsonFormat.parser().merge 之前从收到的 JSON 中删除字段。

【讨论】:

好的,很好的信息,谢谢!我最终提供了自己的 POJO,它反映了 ReceivedMessage protobuf,使用 com.fasterxml.jackson.databind.ObjectMapper 反序列化 json,并以这种方式提取有效负载。

以上是关于谷歌云平台推送订阅发送重复消息 ID 字段的主要内容,如果未能解决你的问题,请参考以下文章

谷歌云消息“未注册”失败并取消订阅最佳做法?

谷歌云存储功能在订阅者连接时发送已发送的消息

新的谷歌云消息 API

谷歌云消息沙盒

谷歌云发布订阅延迟消息

谷歌云消息逻辑解决方案