Kotlin + gradleでgRPCプロトコル定義ファイル(.proto)のvendoringにprotodepをつかってみた


gRPCのプロトコル定義ファイル(.proto)の管理を考えていきたい。gRPCを導入するプロジェクトであれば.protoファイルの運用方法は課題である。

プロトコル定義ファイル(.proto)の運用課題

gRPCはプロトコル定義ファイル(.proto)から生成したプログラムをもとにサーバとクライアントに分かれ実装していくことになる。Microservicesではサーバとクライアントが別レポジトリに分かれ開発を行うことが多い。それぞれのレポジトリではマスタの.protoファイルを何処に置いて参照すれば良いだろうか。この課題は言語が違うクライアントとサーバ間でも同じことが言えるだろう。

そしてもう1つの課題は.protoファイルのバージョン管理だ。開発中のプロトコル定義に最新のプロトコル定義を干渉させたくない。開発中はクライアントとサーバは同じ世代のプロトコル定義を参照していることを再現しなくてはならない。

このような課題を解決してくれるのが protodepだ。

protodepはプロトコル定義ファイル(.proto)のvendoringツールである。
今回のエントリでは protodepをGradleビルドシステムに導入した内容をまとめていく。

※protodepの使い方はREADMEにあるので合わせて参照してください。

protodepをGradleタスクに追加する

※ 開発するプロジェクトの言語はKotlinを想定

開発中はプロジェクト内の.protoファイルからProtocolBufferを生成する必要がある。protobuf-gradle-pluginを有効にすればProtocolBufferを生成するタスクが追加される。導入方法は grpc/grpc-javaを参照していただきたい。

GitHub - grpc/grpc-java: The Java gRPC implementation. HTTP/2 based RPC

protobuf-gradle-pluginを有効にすると generateProtoのタスクが追加される。このタスクを実行することでプロジェクト内の.protoファイルからProtocolBufferが生成できる。

そしてgenerateProtoのタスクの前にprotodepを実行すればリモートにある.protoファイルのプロトコル定義のバージョンの固定を担保したうえでProtocolBufferが生成できる。 settings.gradleに次のようなタスクを追加した。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
task protoDep {
    def identity_file = "id_rsa"
    if (findProperty("identityFile") != null) {
        identity_file = findProperty("identityFile")
    }
    def forceUpdate = ""
    if (findProperty("forceUpdate") != null || findProperty("forceUpdate") == true) {
        forceUpdate = "-f"
    }
    println forceUpdate
    doLast() {
        exec {
            commandLine = ["protodep", forceUpdate, "--identity-file=${identity_file}", "up"]
        }
    }
}

tasks.whenTaskAdded { task ->
    if (task.name == "generateProto" && !project.hasProperty("IGNORE_PROTO_DEP")) {
        task.dependsOn protoDep
    }
}

複数人で開発することを想定して identityFileのgradle propertyを追加している。個人の認証ファイルをビルド時に指定できる。

実行した結果は次のようになる。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
$ ./gradlew clean generateProto build

:cleanProtoGen
:clean
:extractIncludeProto
:extractProto UP-TO-DATE
:protoDep
[INFO] force update = false
[INFO] identity file = id_rsa
[INFO] use SSH protocol
[INFO] Getting github.com/nsoushi/spring5-kotlin-application-proto
:generateProto
:processResources
・・・

generateProtoのタスクの前に protoDepのタスクが実行され.protoファイルをvendoringしてくれる。

.protoファイルをアップデートしたい場合は次のように実行する。

1
$ ./gradlew clean generateProto build -PforceUpdate=true

protodepの-fオプションを有効にしてくれる。
リモートの.protoファイルをProtocolBufferの生成するときに固定するか更新するか選択することができる。

まとめ

コード

settings.gradleはgithubから参照できます。