Rails + SpringBootでgRPCする方法について色々調べた

RailsのバックエンドとしてSpring Bootを置いてgRPCでやりとりするみたいなのをどう実現するかを調べている

RubyからgRPCを使う

shiladitya-bits.github.io

クライアント側はこれが参考になった。proto からGemの中身を生成して配布するの良さそう。 クライアント側でgRPCを扱うコードはこんな感じになる

  stub = Snip::UrlSnipService::Stub.new('0.0.0.0:50052', :this_channel_is_insecure)
  req = Snip::SnipRequest.new(url: 'http://shiladitya-bits.github.io')
  resp_obj = stub.snip_it(req)

Spring BootでgRPCを使う

これを使うのが楽そう。 @GRpcServiceアノテーションを付与するだけで、 SpringgRPC を共存させることができる。

github.com

    @GRpcService
    public static class GreeterService extends  GreeterGrpc.GreeterImplBase{
        @Override
        public void sayHello(GreeterOuterClass.HelloRequest request, StreamObserver<GreeterOuterClass.HelloReply> responseObserver) {
            final GreeterOuterClass.HelloReply.Builder replyBuilder = GreeterOuterClass.HelloReply.newBuilder().setMessage("Hello " + request.getName());
            responseObserver.onNext(replyBuilder.build());
            responseObserver.onCompleted();
        }
    }

実際にアプリケーションを作るにあたって

クライアントをどこで作るか

.proto からクライアントをどこで作って配布するかみたいなのを考えていた。 .proto を vendoringするためのツールを作っている方もいるみたい。

github.com

現在のところはgradleのビルドの中でRubyクライアントを作っている。クライアントが決まっていて1言語だけなら、これがコスパよいかなという気がする。

github.com

このgradleのプラグインで、Rubyクライアントも生成できそうなんだけど、なぜかCLIgrpc_tools_ruby_protoc -Iproto --ruby_out=lib --grpc_out=lib proto/*.proto としたときにできる *_services_pb.rb が生成されない。 このIssueと関連ありそうな気がするけど、コードまでは追えてない。

github.com

しょうが無いので、無理やりgradleの中でコマンドを実行してRubyのクライアントを生成するようにしている。 キレイにやるならCIで生成するとかかなぁ。

エラーハンドリング

まだ良くわかってないが、この辺を読んで見るつもり。というか、この公式のexamplesもっと早く見ておけばよかった・・・

色々資料を読んでいると、エラーの詳細を返したいときはメタデータに入れるのが一般的なのかなー。例えばバリデーション的なものをやりたいときに、gRPCからどんな風にエラーを返せばいいんだろ。

grpc/examples/ruby/errors_and_cancellation at master · grpc/grpc · GitHub

今のところの感想

なんとなく行けそうなイメージは出てきたけど、まだまだ色々調べなきゃいけないことが多い。

gRPCだけでなく、SpringBootやgradleとかもまだまだ「全然わからない。俺は雰囲気で(ry」って感じなので、ちゃんと作っていくとまだまだ色々ありそうな予感。