Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
Help us understand the problem. What is going on with this article?

CloudPubSubでhashデータをpublishするときにハマった

More than 1 year has passed since last update.

Cloud Pubsubにhashでメッセージを送ったときに、全部文字列になってハマったよって話

結論

hashデータはto_jsonするなどしてstring化してpublishしよう

何が起きたか

RubyでPubsubにpublishする際、色んなパラメータを渡したいのでHashに色々突っ込んで送っていた

Google::Cloud::Pubsub(params).topic(:hoge_topic).publish data

これでpubsubが普通にkickできるのだが、Cloud Functionsのattributesで受け取った際にevent['attributes']['hoge'] == Trueのような比較で想定通りに通らなくなった。

よくよくデータを見てみたところ、Ruby側でHashを送るとkey:valueのペアごとにstring化されてしまっている。

publish側

require 'google/cloud/pubsub'

pubsub = Google::Cloud::Pubsub.new({ project_id: 'consulting-cloud-dev', credentials: 'credential.json'})
pubsub.topic(:hoge_topic).publish({ 'true': true, 'false': false, 'nil': nil, 'num': 1, 'float': 3.4 })

subscribe側 (python on Cloud Functions)

def hello_pubsub(event, context):
    print(event['attributes'])

Stackdriver上のログ

{'false': 'false', 'float': '3.4', 'nil': '', 'num': '1', 'true': 'true'}

全部''で囲われていて文字列扱いになっている。うーん。

ライブラリの実装を見る

ライブラリ側の実装を見ると、Hashの場合はそれぞれstring化されてる。
https://github.com/googleapis/google-cloud-ruby/blob/master/google-cloud-pubsub/lib/google/cloud/pubsub/batch_publisher.rb#L91

コメントにはprotobuf definitionと書いてあるのでprotobufを想定しているということなのか。
なるほどー。確かにJSONとは限らないですね。

def create_pubsub_message data, attributes
  attributes ||= {}
  if data.is_a?(::Hash) && attributes.empty?
    attributes = data
    data = nil
  end
  # Convert IO-ish objects to strings
  if data.respond_to?(:read) && data.respond_to?(:rewind)
    data.rewind
    data = data.read
  end
  # Convert data to encoded byte array to match the protobuf defn
  data_bytes = \
    String(data).dup.force_encoding(Encoding::ASCII_8BIT).freeze

  # Convert attributes to strings to match the protobuf definition
  attributes = Hash[attributes.map { |k, v| [String(k), String(v)] }]

  Google::Pubsub::V1::PubsubMessage.new data: data_bytes,
                                        attributes: attributes
end

地味に何故メッセージ送ってるのに、Cloud Functions側でmessageに入らずattributesに入ってくるのかもここで把握。
この関数で切り替わってたのか。

json化すればok

to_jsonつけた

require 'google/cloud/pubsub'

pubsub = Google::Cloud::Pubsub.new({ project_id: 'consulting-cloud-dev', credentials: 'credential.json'})
pubsub.topic(:hoge_topic).publish({ 'true': true, 'false': false, 'nil': nil, 'num': 1, 'float': 3.4 }.to_json)

subscribe側のログ

{"true":true,"false":false,"nil":null,"num":1,"float":3.4}

nilはnullになってるし、値も元の型になってる。

messageはstring化して送りましょう。

kshibata101
サーバーエンジニア 某ソーシャルゲーム会社でフロント(JS)2年、サーバー(PHP)3年ほど経験後、 現在はVISITS Technologiesという会社でサーバーエンジニアとして従事中。 会社としてGCPに舵切っているところでもあり、主にGCP関連技術を発信していこうと思います。 PHP/Ruby(Rails)/JS/MySQL/Redis/GCP/AWS
vis-its
独自技術ideagramを用いて、人々の「創造性」や「目利き力」の定量化を行い、イノベーター人材の発掘/育成、科学的イノベーション創発支援を行っています。
https://visits.world
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away