最近gRPCが楽しくて仕方ない. いろいろやったけど,やっぱりgoogleが作っただけあって,goで書いてあるサンプルは多いし,goでgRPCは使いやすい(その話は別のところで話したい).
のだけれど,どうも最近scalaを書くことが多く,そしてscalaでgRPCしているサンプルがあまりないのでメモを残しておく.
あと,gRPCの説明とかは特にしないので,そいうのは別の記事を参考にしていただきたい. チュートリアル的な実装も,goでやったほうが楽だしわかりやすいと思うよ(俺は).
ProtocolBufferを使えるようになるまで
という話の前に,
とても参考になるし,ここのサンプルだけで今から書こうとしていることのほとんどすべてが網羅されている. むしろこれをちゃんと読めばこの記事は読まなくていい.
基本的にはこれとまったく同じで,ScalaPBを使う.
project/plugins.sbt
あたりに,
addSbtPlugin("com.thesamet" % "sbt-protoc" % "0.99.12") libraryDependencies += "com.trueaccord.scalapb" %% "compilerplugin" % "0.6.6"
という記述をしておく.
で,build.sbt
を
import com.trueaccord.scalapb.compiler.Version.{grpcJavaVersion, scalapbVersion, protobufVersion} /* 中略 */ libraryDependencies ++= Seq( /* 中略 */ "io.grpc" % "grpc-netty" % grpcJavaVersion, "com.trueaccord.scalapb" %% "scalapb-runtime" % scalapbVersion % "protobuf", "com.trueaccord.scalapb" %% "scalapb-runtime-grpc" % scalapbVersion, "io.grpc" % "grpc-all" % grpcJavaVersion ) PB.targets in Compile := Seq(scalapb.gen() -> ((sourceManaged in Compile).value / "protobuf-scala")) PB.protoSources in Compile += (baseDirectory in LocalRootProject).value / "protocol"
みたいなことを書いておく.
最後のprotoSources
では,実際に .proto
ファイルを入れておくディレクトリを指定した.
これで,$ sbt compile
とかしておけば,ProtocolBufferからコードが自動生成される.
gRPCサーバの中身を書く
自動生成されたコードだけでは,ただのライブラリでしかないので,ここからサーバを起動できるようにしよう.
package grpc import io.grpc.{Server, ServerBuilder} // ProtocolBufferから自動生成されたライブラリたち import users.users.{RequestType, UsersGrpc} import scala.concurrent.ExecutionContext object GrpcServer { private val logger = Logger.getLogger(classOf[GrpcServer].getName) def main(args: Array[String]): Unit = { val server = new GrpcServer(ExecutionContext.global) server.start() server.blockUnitShutdown() } private val port = sys.env.getOrElse("SERVER_PORT", "50051").asInstanceOf[String].toInt } class GrpcServer(executionContext: ExecutionContext) { self => private val port = sys.env.getOrElse("SERVER_PORT", "50051").asInstanceOf[String].toInt private[this] var server: Server = null def start(): Unit = { server = ServerBuilder.forPort(port).addService( UsersGrpc.bindService(new UsersImpl, executionContext) ).build.start Logger.info("gRPC server started, listening on " + port) sys.addShutdownHook { Logger.info("*** shutting down gPRC server since JVM is shutting down") self.stop() } } def stop(): Unit = { if (server != null) { Logger.info("*** gRPC server shutdown") server.shutdown() } } def blockUnitShutdown(): Unit = { if (server != null) { server.awaitTermination() } } private class UsersImpl extends UsersGrpc.Users { /* 中略 */ } }
というようなサーバを起動できるobjectを用意して,こいつを src/main/scala/grpc/server.scala
みたいなところに保存しておく.
これで, $ sbt run
すれば,このgrpcサーバが起動するわけだ.
こんなことをするようなサンプルを作っておいた.