gRPC で go-proto-validators を .proto に import したら grpc_cli がうまく使えない
(=˘ ꒳ ˘=) 最近 gRPC を始めたけどパス解決周りが Protocol Buffer 層も相まって複雑で混乱する...
hello.proto に簡単なバリデーションを組み込んで Go で吐き出して grpc_cli で動作確認しようとしたらハマって、そしてそのまま解決していない件になります。バリデーション処理ではなく主に Protocol Buffer の import 周りの試行錯誤のお話になります。
- 素朴に go-proto-validators を import したところ...
- とりあえずリフレクションを無効化して試行錯誤する
- symlink を張った状態でリフレクションを有効化してみる
- Issue を漁ってみる...
素朴に go-proto-validators を import したところ...
- プロジェクト: https://github.com/asa-taka/hello-validated-grpc
- バリデーションを組み込んだあたりのコード: https://github.com/asa-taka/hello-validated-grpc/commit/0badbe6c2bf7ff49a411e50d0b642573e64a6147
今回対象にする hello.proto は以下のようなものです。
go-proto-validators/validator.proto
を import
しています。
syntax = "proto3"; package hello; import "github.com/mwitkow/go-proto-validators/validator.proto"; service GreetingService { rpc Hello(GreetingRequest) returns (GreetingResponse); } message GreetingRequest { string name = 1 [(validator.field) = {string_not_empty: true}]; } message GreetingResponse { string message = 1 [(validator.field) = {string_not_empty: true}]; }
これを protoc
して Go ライブラリを吐き出してサーバを実装して grpc_cli で叩いたところ、症状としては以下のようになりました。
grpc_cli ls
は動くgrpc_cli ls -l
は動かないgrpc_cli call ...
も動かない
$ grpc_cli ls localhost:10000 grpc.reflection.v1alpha.ServerReflection hello.GreetingService $ grpc_cli ls -l localhost:10000 [libprotobuf ERROR google/protobuf/descriptor.cc:3592] Invalid proto descriptor for file "api/hello.proto": [libprotobuf ERROR google/protobuf/descriptor.cc:3595] api/hello.proto: Import "github.com/mwitkow/go-proto-validators/validator.proto" was not found or had errors. filename: grpc_reflection_v1alpha/reflection.proto package: grpc.reflection.v1alpha; service ServerReflection { rpc ServerReflectionInfo(stream grpc.reflection.v1alpha.ServerReflectionRequest) returns (stream grpc.reflection.v1alpha.ServerReflectionResponse) {} } $ grpc_cli call localhost:10000 Hello "name: 'test'" [libprotobuf ERROR google/protobuf/descriptor.cc:3592] Invalid proto descriptor for file "api/hello.proto": [libprotobuf ERROR google/protobuf/descriptor.cc:3595] api/hello.proto: Import "github.com/mwitkow/go-proto-validators/validator.proto" was not found or had errors. Method name not found
どれも github.com/mwitkow/go-proto-validators/validator.proto が見つからないと言われていますね。
gRPC や Protocol Buffer 周りのパス解決をよく理解しておらず、さらにリフレクション経由というローカルとはいえネットワークを噛ませたパス解決がどうなるかも相まって二重三重で混乱します。
とりあえずリフレクションを無効化して試行錯誤する
問題を簡略化したいので、とりあえずリフレクションはコメントアウトして grcp_cli --protofile
を直接指定するやり方で実行してみます。
https://github.com/grpc/grpc/blob/master/doc/command_line_tool.md#call-a-remote-method の「User local proto file」のやり方です。
grpc_cli
にも --proto_path
を指定できるみたいですが protoc
のように複数指定してもうまく行かず、結局 .proto のパスを同一起点から解決できればいいんだろうということで、プロジェクトルートから依存パッケージを辿れるような symlink を張ったら動くことには動きました。
$ echo $GOPATH /Users/asa-taka $ pwd /Users/asa-taka/src/github.com/asa-taka/hello-validated-grpc $ tree . ├── Makefile ├── api │ ├── hello.pb.go │ ├── hello.proto │ └── hello.validator.pb.go ├── github.com -> /Users/asa-taka/src/github.com/ ├── google -> /Users/asa-taka/src/github.com/google/protobuf/src/google └── server.go $ grpc call localhost:10000 Hello "name: 'test'" --protofiles=api/hello.proto connecting to localhost:10000 message: "Hello, test." Rpc succeeded with OK status
流石に不便なのでもっといい方法が用意されているか、何かしら自分が間違えているのを期待しています。
一応どの symlink を張ったか解説しておくと
github.com -> ~/src/github.com/
はgo-proto-validators
を辿る用google -> ~/src/github.com/google/protobuf/src/google/
は protobuf の基本定義に必要らしいです- 中身(詳細は把握してません...): https://github.com/google/protobuf/tree/master/src/google/protobuf
ちなみに grpc_cli ls
は動作しませんでした。リフレクション専用のコマンドみたいですね。
$ grpc ls -l localhost:10000 --protofiles=api/hello.proto Received an error when querying services endpoint.
symlink を張った状態でリフレクションを有効化してみる
この状態からリフレクションのコメントアウトを外してみます。初めの状態と特に症状は変わりませんでした。依然として github.com/mwitkow/go-proto-validators/validator.proto が見つからないと言われています。
$ grpc ls localhost:10000 grpc.reflection.v1alpha.ServerReflection hello.GreetingService $ grpc ls -l localhost:10000 [libprotobuf ERROR google/protobuf/descriptor.cc:3592] Invalid proto descriptor for file "api/hello.proto": [libprotobuf ERROR google/protobuf/descriptor.cc:3595] api/hello.proto: Import "github.com/mwitkow/go-proto-validators/validator.proto" was not found or had errors. filename: grpc_reflection_v1alpha/reflection.proto package: grpc.reflection.v1alpha; service ServerReflection { rpc ServerReflectionInfo(stream grpc.reflection.v1alpha.ServerReflectionRequest) returns (stream grpc.reflection.v1alpha.ServerReflectionResponse) {} } $ grpc call localhost:10000 Hello "name: 'test'" [libprotobuf ERROR google/protobuf/descriptor.cc:3592] Invalid proto descriptor for file "api/hello.proto": [libprotobuf ERROR google/protobuf/descriptor.cc:3595] api/hello.proto: Import "github.com/mwitkow/go-proto-validators/validator.proto" was not found or had errors. Method name not found
苦し紛れに --proto_path=.
を指定してみても改善せず。
$ grpc ls -l localhost:10000 --proto_path=. [libprotobuf ERROR google/protobuf/descriptor.cc:3592] Invalid proto descriptor for file "api/hello.proto": [libprotobuf ERROR google/protobuf/descriptor.cc:3595] api/hello.proto: Import "github.com/mwitkow/go-proto-validators/validator.proto" was not found or had errors. filename: grpc_reflection_v1alpha/reflection.proto package: grpc.reflection.v1alpha; service ServerReflection { rpc ServerReflectionInfo(stream grpc.reflection.v1alpha.ServerReflectionRequest) returns (stream grpc.reflection.v1alpha.ServerReflectionResponse) {} } $ grpc call localhost:10000 Hello "name: 'test'" --proto_path=. [libprotobuf ERROR google/protobuf/descriptor.cc:3592] Invalid proto descriptor for file "api/hello.proto": [libprotobuf ERROR google/protobuf/descriptor.cc:3595] api/hello.proto: Import "github.com/mwitkow/go-proto-validators/validator.proto" was not found or had errors. Method name not found
リフレクションサービスは動いているけれど、import が解決できず GreetingService は動かないという...
リフレクション経由で .proto の import を解決する方法ってないんでしょうか。今のところ symlink を張るくらいの解決策しか見つかっておらず、このままだとちょっと不便なんですよね...何かあるはず、というかみんなどうやってるのか...
Issue を漁ってみる...
コマンドのヘルプもドキュメントもあまり充実してはいないので、諦めて Issue を辿っていきます。
- grpc_cli does not work if proto file contains google.protobuf.Timestamp · Issue #1163 · grpc/grpc-go · GitHub
- https://github.com/grpc/grpc-go/issues/1163#issuecomment-292168123
grpc_cli ls
は--proto_path
や--protofile
に対応していないらしい
- https://github.com/grpc/grpc-go/issues/1163#issuecomment-292168123
- grpc_cli does not work if proto file contains google.protobuf.Timestamp · Issue #10304 · grpc/grpc · GitHub
- 今回のとは少しエラーの様子が違うけれど
google.protobuf.Timestamp
を使った時も、ちょっとした対応を覚悟しなければならなそう
- 今回のとは少しエラーの様子が違うけれど
- ptypes: Path to proto file in timestamp.pb.go makes use of grpc awkward · Issue #298 · golang/protobuf · GitHub
- 色々辿ってこの Issue にたどり着きましたがもう何がなんだか...
ざっと見たところ google.protobuf.Timestamp
というよく使われる type/message を使った時も面倒なことになっているらしいですが、詳しいことは読み取る気力がわきませんでした。こちらの方が事象としてはよりシンプルな気もするので、こちら側から攻めてみてもいいかもしれませんね。どうせ日付型も使うことになるでしょうし。
...で、別記事で日付型の import を試してみたところ普通に動いてしまったというわけで、本件に関しては継続して探っていきたいと思います...
それにしても Issue を辿っていると protobuf と grpc と grpc-go をたらい回しになって、なんか、その、疲れます...