$30 off During Our Annual Pro Sale. View Details »

grpc-kotlinはどこまでKotlin化できるのか?

 grpc-kotlinはどこまでKotlin化できるのか?

2020年6月17日(水) 「集まれKotlin好き!Kolint愛好会 vol.22 @オンライン」の談義資料です。

Takehata Naoto

June 17, 2020
Tweet

More Decks by Takehata Naoto

Other Decks in Programming

Transcript

  1. grpc-javaでの実装(抜粋) class GreeterImpl : GreeterGrpc.GreeterImplBase() { override fun sayHello(req: HelloRequest,

    responseObserver: StreamObserver<HelloReply>) { val reply = HelloReply.newBuilder().setMessage("Hello ${req.name}").build() responseObserver.onNext(reply) responseObserver.onCompleted() } } Observerパターンで実装されている
  2. grpc-kotlinでの実装(抜粋) class HelloWorldService : GreeterGrpcKt.GreeterCoroutineImplBase() { override suspend fun sayHello(request:

    HelloRequest) = HelloReply .newBuilder() .setMessage("Hello ${request.name}") .build() } ・親クラスをKotlin化したものに変更 ・suspend関数に変更 ・Observerを使わなくなった
  3. grpc-javaでの実装(抜粋) fun greet(name: String) { val blockingStub: GreeterGrpc.GreeterBlockingStub = GreeterGrpc.newBlockingStub(channel)

    val request = HelloRequest.newBuilder().setName(name).build() val response: HelloReply = blockingStub.sayHello(request) logger.info("Greeting: ${response.message}") } Stubを生成して実行
  4. grpc-kotlinでの実装(抜粋) suspend fun greet(name: String) = coroutineScope { val stub:

    GreeterCoroutineStub = GreeterCoroutineStub(channel) val request = HelloRequest.newBuilder().setName(name).build() val response = async { stub.sayHello(request) } println("Received: ${response.await().message}") } ・Kotlin化されたStubを使う ・Stubの関数もsuspend関数になっているため、非同期で実行する
  5. Stubの親クラス abstract class AbstractCoroutineStub<S: AbstractCoroutineStub<S>>( channel: Channel, callOptions: CallOptions =

    CallOptions.DEFAULT ): AbstractStub<S>(channel, callOptions) Serviceと同様Javaのクラスを継承している(Javaに依存している)
  6. ServerInterceptor @GRpcGlobalInterceptor @Order(10) class LoggingInterceptor : ServerInterceptor { companion object

    { private val log = LoggerFactory.getLogger(LoggingInterceptor::class.java) } override fun <ReqT : Any, RespT : Any> interceptCall(call: ServerCall<ReqT, RespT>, headers: Metadata, next: ServerCallHandler<ReqT, RespT>): ServerCall.Listener<ReqT> { log.info("method name=${call.methodDescriptor.fullMethodName}") return next.startCall(call, headers) } }
  7. ClientIterceptor class MetadataClientInterceptor : ClientInterceptor { companion object { private

    val log = LoggerFactory.getLogger(MetadataClientInterceptor::class.java) } override fun <ReqT, RespT> interceptCall(method: MethodDescriptor<ReqT, RespT>?, callOptions: CallOptions?, next: Channel): ClientCall<ReqT, RespT>? { return object : SimpleForwardingClientCall<ReqT, RespT>(next.newCall(method, callOptions)) { override fun start(responseListener: Listener<RespT>?, headers: Metadata) { headers.put(Metadata.Key.of(“example”, Metadata.ASCII_STRING_MARSHALLER), “Example”) // ・・・
  8. Channel、message suspend fun greet(name: String) = coroutineScope { val channel

    = ManagedChannelBuilder.forAddress("localhost", 6565) .usePlaintext().build() val stub: GreeterCoroutineStub = GreeterCoroutineStub(channel) val request = HelloRequest.newBuilder().setName(name).build() val response = async { stub.sayHello(request) } println("Received: ${response.await().message}") }
  9. messageをもしデータクラスにできたら・・・ suspend fun greet(name: String) = coroutineScope { val channel

    = ManagedChannelBuilder.forAddress("localhost", 6565) .usePlaintext().build() val stub: GreeterCoroutineStub = GreeterCoroutineStub(channel) val request = HelloRequest (name) val response = async { stub.sayHello(request) } println("Received: ${response.await().message}") }
  10. grpc-javaでの実装(抜粋) @GRpcService(interceptors = [MessageInterceptor::class]) class ExampleGrpcService : ExampleGrpc.ExampleImplBase() { override

    fun createMessage(request: CreateMessageRequest, responseObserver: StreamObserver<CreateMessageResponse>) { // ・・・
  11. grpc-kotlinでの実装(抜粋) @GRpcService(interceptors = [MessageInterceptor::class]) class ExampleGrpcService : ExampleGrpcKt.ExampleCoroutineImplBase() { override

    suspend fun createMessage(request: CreateMessageRequest): CreateMessageResponse { // ・・・ もともとの実装にgrpc-kotlinを組み込んだ形
  12. grpc-javaでの実装(抜粋) @RequestMapping("/createmessage") fun createMessage(@RequestBody request: RestCreateMessageRequest): String { val createMessageRequest

    = CreateMessageRequest.newBuilder().setName(request.name).build() val channel = ManagedChannelBuilder.forAddress("localhost", 6565) .usePlaintext().build() val stub = ExampleGrpc.newBlockingStub(channel) val response = stub.createMessage(createMessageRequest) return response.message.text }
  13. grpc-kotlinでの実装(抜粋) @PostMapping("/createmessage") suspend fun createMessage(@RequestBody request: RestCreateMessageRequest): String { val

    createMessageRequest = CreateMessageRequest.newBuilder().setName(request.name).build() val channel = ManagedChannelBuilder.forAddress("localhost", 6565) .usePlaintext().build() val stub = ExampleGrpcKt.ExampleCoroutineStub(channel) val response = async { stub.createMessage(createMessageRequest) } return response.await().message.text }