今回は、RailsからgRPCのリクエストしてみたので、その方法を書き残しておきます。
必要なGemのインストール
Railsプロジェクトの準備は済んでいるものとして、Gemをインストールします。
Gemfile に以下を追加して、 bundle install
します。
gem 'grpc' gem 'grpc-tools'
Protocol Buffers による定義
gRPCでは、Protocol Buffers(Protobuf)を利用して通信を行います。
ProtobufはJSONやXMLのような構造化データのフォーマットです。
JSONやXMLよりも高速に動作するようにでき、データがバイナリ形式のため、データサイズを小さく抑えることができるメリットがあります。
Protobufでは、以下のようにRPCの定義と、構造化データの定義をすることができます。
// proto/ping.proto // Protobufのバージョン指定 syntax = "proto3"; // パッケージの定義 package ping; // Goで使う場合の、Goでのパッケージ名 option go_package = "proto/ping"; // RPCメソッドの定義 service PingService { // Unary RPC rpc Ping(Empty) returns (Pong) {} // Server streaming RPC rpc PingStream(PingRequest) returns (stream Pong) {} } // RPCの送信/受信時のデータ構造の定義 message Empty {} message PingRequest { int32 count = 1; } message Pong { string text = 1; }
Protobufの定義から、Rubyのコードを生成する
Protobufの定義が済んだので、ここからRubyのコードを生成します。
コード生成には、 grpc_tools_ruby_protoc
を実行します。
cd "$RAILS_DIR" bundle exec grpc_tools_ruby_protoc \ -I ../proto \ --ruby_out=lib \ --grpc_out=lib \ ../proto/ping.proto
これにより、lib以下にコードが生成されます。
lib └ ping_pb.rb └ ping_services_pb.rb
gRPCクライアントとしてRailsから呼び出す
最後にRailsからgRPCサーバーを呼び出してみます。
class ApplicationController < ActionController::API # Unary RPC def ping pong = ping_service.ping(Ping::Empty.new) render json: {pong: pong.text} end # Server streaming RPC def ping_stream pong = ping_service.ping_stream(Ping::PingRequest.new(count: 3)) render json: {pong: pong.map{ |p| p.text }.inspect} end private def ping_service @client ||= Ping::PingService::Stub.new('localhost:5300', :this_channel_is_insecure) end end
その他
Gruf というGemがあるのですが、クライアントとして利用する場合には、そこまでメリットが強くなさそうだったため、今回は利用を見送りました。
まとめ
今回は、RailsをgRPCクライアントとして、gRPCの通信をする方法を試してみたので、まとめておきました。
Protobufの定義の仕方や、コード生成ができれば、呼び出し自体はそれなりに簡単にできるようです。
ただ、本番利用を想定すると、エラーハンドリングや、通信中のアプリケーション終了時の扱いなどを気をつける必要はありそうです。