Upgrade to Pro — share decks privately, control downloads, hide ads and more …

gRPC with Kotlin Coroutines on Android

Mohit S
January 19, 2021

gRPC with Kotlin Coroutines on Android

Learn about how to use gRPC on Android.

Mohit S

January 19, 2021
Tweet

More Decks by Mohit S

Other Decks in Programming

Transcript

  1. Mohit Sarveiya gRPC with Kotlin Coroutines on Android @heyitsmohit

  2. gRPC with Kotlin Coroutines • Using gRPC on Android •

    Authentication • Retries & Hedging • Debugging tools
  3. RPC g RPC (Remote Procedure Call) Framework

  4. • Polyglot implementation • Coroutines Support gRPC

  5. Server(Go) gRPC Client(Kotlin) Client(Swift)

  6. Server(Go) gRPC service Client(Kotlin) Client(Swift)

  7. Server(Go) gRPC service service MyService { rpc subscribe( . .

    ) }
  8. • Unary RPC call • Server streaming • Client streaming

    • Bidirectional streaming RPC Calls
  9. gRPC service MyService { rpc subscribe( . . ) }

    Proto buffer file Protoc Service Class
  10. • Generated class • Handles incoming requests • Send back

    data Service Class
  11. Server(Go) gRPC service Client(Kotlin) Client(Swift)

  12. Server(Go) gRPC service Client(Kotlin) Client(Swift) service service

  13. gRPC service MyService { rpc subscribe( . . ) }

    Proto buffer file Protoc Client Stub
  14. • Generated class. • Make Requests. • Creates response types.

    Client Stub
  15. Server(Go) gRPC service Client(Kotlin) Client(Swift) Client Stub

  16. Server(Go) gRPC service Client(Kotlin) Client(Swift) rpc rpc

  17. Server(Go) gRPC service Client(Kotlin) Client(Swift) rpc rpc HTTP 2

  18. Android gRPC Server

  19. grpc/grpc-kotlin Code ! Issues Pull Requests gRPC-Kotlin/JVM - An RPC

    library and framework grpc-kotlin-stub v0.1.4 protoc-gen-grpc-kotlinstub v0.1.4 grpc-kotlin-stub-lite v0.1.4 Bazel Build passing Gradle Build passing A Kotlin/JVM implementation of gRPC: A high performance, open source, general RPC framework that puts mobile and HTTP/2 first.
  20. Use Case • Tracks your route.

  21. Use Case • Tracks your route. • Get a place

    from location.
  22. Use Case • Tracks your route. • Get a place

    from location. • List Places around location.
  23. Use Case • Tracks your route. • Get a place

    from location. • List Places around location. • Chat with others at location. Shoreline Golf links 2940 N Shoreline Blvd Mountain View, CA 94043 Start typing
  24. Android gRPC Server gRPC

  25. gRPC service service MyService { rpc subscribe( . . )

    } gRPC Server
  26. protocolbuffers/protobuf Code ! Issues Pull Requests Protocol Buffers - Google’s

    data interchange format Protocol Buffers (a.k.a., protobuf) are Google's language-neutral, platform-neutral, extensible mechanism for serializing structured data. Gradle Build passing
  27. Service syntax = “proto3”; Protocol Buffer Version

  28. Service syntax = “proto3”; service Places { } Declare Service

  29. RPC Call Types • Unary • Server Streaming • Client

    Streaming • Bidirectional
  30. Use Case • Get a place from location 
 (Latitude,

    Longitude) Place
  31. Unary RPC Call Client Server Location

  32. syntax = “proto3”; service Places { rpc GetPlace(Location) returns (Place)

    {}; } Unary RPC Call keyword
  33. Unary RPC Call Name of RPC call service Places {

    rpc GetPlace() }
  34. Unary RPC Call service Places { rpc GetPlace(Location) } Request

  35. Unary RPC Call service Places { rpc GetPlace(Location) returns (Place)

    {}; } Response
  36. Unary RPC Call syntax = “proto3”; service Places { rpc

    GetPlace(Location) returns (Place) {}; } Unary RPC Call
  37. Unary RPC Call syntax = “proto3”; service Places { rpc

    GetPlace(Location) returns (Place) {}; } Define messages
  38. Unary RPC Call message Location { double latitude = 1;

    double longitude = 2; } } Keyword
  39. Unary RPC Call service Places { message Location double latitude

    = 1; double longitude = 2; } } Message name
  40. Unary RPC Call message Location { double latitude = 1;

    double longitude = 2; } Fields
  41. message Location { double latitude = 1; double longitude =

    2; } Unary RPC Call Type
  42. message Location { double latitude = 1; double longitude =

    2; } Unary RPC Call .proto Type C++ Java Go double double Double * f l oat64 int32 int32 int *int32 Int64 long int/long *int64 https://developers.google.com/protocol-bu f f ers/docs/overview#scalar
  43. message Location { double latitude = 1; double longitude =

    2; } Unary RPC Call Field numbers
  44. Unary RPC Call syntax = “proto3”; service Places { rpc

    GetPlace(Location) returns (Place) {}; } Define Place
  45. Unary RPC Call message Place { string name = 1;

    Location location = 2; } Name & Location
  46. Unary RPC Call message Place { string name = 1;

    Location location = 2; 
 PlaceType placeType = 3; } Enum
  47. Unary RPC Call message Place { 
 PlaceType placeType =

    3; enum PlaceType { Landmark = 0; Driving_Range = 1; Golf_Course = 2; Restaurant = 3; Retail = 4; } Enum
  48. Unary RPC Call message Place { string name = 1;

    Location location = 2; 
 PlaceType placeType = 3; enum PlaceType { … } 
 int64 checkins = 4; int64 comments = 5; } Int Scaler Types
  49. Unary RPC Call syntax = “proto3”; service Places { rpc

    GetPlace(Location) returns (Place) {}; }
  50. Use Case • Check into place 
 Location Empty Response

  51. Unary RPC Call syntax = “proto3”; service Places { rpc

    CheckIn(Location) returns () {}; }
  52. Unary RPC Call syntax = “proto3”; service Places { rpc

    CheckIn(Location) returns () {}; } How do we return an empty?
  53. Code ! Issues Pull Requests protocolbuffers/protobuf protobuf/src/google/protobuf/empty.proto message Empty {

    }
  54. Well Known Types • Empty • Timestamp • Duration

  55. Unary RPC Call syntax = “proto3”; 
 import "google/protobuf/empty.proto"; service

    Places { rpc CheckIn(Place) returns () {}; } Import
  56. Unary RPC Call syntax = “proto3”; service Places { rpc

    CheckIn(Location) returns (google.protobuf.Empty) {}; } How do we return an empty?
  57. RPC Call Types • Unary • Server Streaming • Client

    Streaming • Bidirectional
  58. Use Case • List Places around location. Location(s) List<Place>

  59. Server Streaming Client Server Location(s)

  60. Server Streaming Client Server Stream of Places

  61. Server Streaming service Places { rpc ListPlaces(Area) returns (stream Place)

    {}; } Server Streaming RPC Call
  62. Server Streaming service Places { rpc ListPlaces(Area) returns (stream Place)

    {}; } Cluster of Locations
  63. Server Streaming message Area { Location lo = 1; Location

    hi = 2; 
 } Cluster of Locations
  64. Server Streaming service Places { rpc ListPlaces(Area) returns (stream Place)

    {}; } stream keyword
  65. Server Streaming service Places { rpc ListPlaces(Area) returns (stream Place)

    {}; } Server Streaming RPC Call
  66. RPC Call Types • Unary • Server Streaming • Client

    Streaming • Bidirectional
  67. Use Case • Tracks your route Location(s) 
 Trip Summary

  68. Client Streaming Client Server Location(s)

  69. Client Streaming Client Server Trip Summary

  70. Client Streaming service Places { rpc RecordTrip(stream Location) returns (TripSummary)

    {}; }
  71. Client Streaming service Places { rpc RecordTrip(stream Location) returns (TripSummary)

    {}; } Client Stream
  72. Client Streaming service Places { rpc RecordTrip(stream Location) returns (TripSummary)

    {}; } Return single message
  73. Client Streaming service Places { rpc RecordTrip(stream Location) returns (TripSummary)

    {}; }
  74. RPC Call Types • Unary • Server Streaming • Client

    Streaming • Bidirectional
  75. Use Case • Chat with others at location • Stream

    of messages Shoreline Golf links 2940 N Shoreline Blvd Mountain View, CA 94043 Start typing
  76. Bidirectional RPC Call Client Server Comments

  77. Bidirectional RPC Call Client Server Replies

  78. Bidirectional RPC Call service Places { rpc Chat(stream Comment) returns

    (stream Comment) {}; } Bidirectional RPC Call
  79. Bidirectional RPC Call service Places { rpc Chat(stream Comment) returns

    (stream Comment) {}; } stream keyword
  80. RPC Call Types • Unary • Server Streaming • Client

    Streaming • Bidirectional
  81. RPC Call Types service Places { rpc GetPlace(Location) returns (Place)

    {}; rpc ListPlaces(Area) returns (stream Place) {}; rpc CheckIn(Place) returns (google.protobuf.Empty) {}; rpc Chat(stream Comment) returns (stream Comment) {}; }
  82. gRPC service MyService { rpc subscribe( . . ) }

    gRPC Server Service
  83. Android gRPC Server gRPC Service Service

  84. Android gRPC Client Stub

  85. Generating Client Stub • Class for messages • Coroutine bindings

    for rpc calls
  86. Generating Builders Proto buffer file Protoc Message Builders class Message

    { static class Builder { Builder set(double value) Location build() } }
  87. Creating Messages message Location { double latitude = 1; double

    longitude = 2; } class Location { static class Builder { Builder setLatitude(double value) Builder setLongitude(double value) Location build() } }
  88. Creating Messages message Location { double latitude = 1; double

    longitude = 2; } Location.newBuilder() .setLatitude(40.9888341) .setLongitude(-73.8502007) .build()
  89. protocolbuffers/protobuf Code ! Issues Pull Requests Kotlin support request #3742

    ! Open issue opened on Oct 12, 2017 comment on opened on Oct 12, 2017 Please support convert to Kotlin 168
  90. Generating Service Proto buffer file Protoc Service class Service {

    fun rpcMethod1(): Flow<Message> 
 fun rpcMethod2(): Flow<Message> }
  91. Generated Client class CoroutineStub { }

  92. Generated Client class CoroutineStub { } rpc GetPlace(Location) returns (Place)

    {};
  93. Generated Client class CoroutineStub { } rpc GetPlace(Location) returns (Place)

    {}; suspend fun getPlace(request: Location): Place
  94. Generated Client class CoroutineStub { } rpc ListPlaces(Area) returns (stream

    Place) {};
  95. Generated Client class CoroutineStub { } rpc ListPlaces(Area) returns (stream

    Place) {}; fun listPlaces(request: Area): Flow<Place> Stream is map to Flow
  96. Generated Client class CoroutineStub { } rpc Chat(stream Comment) returns

    (stream Comment) {};
  97. Generated Client class CoroutineStub { } rpc Chat(stream Comment) returns

    (stream Comment) {}; fun chat(requests: Flow<Comment>): Flow<Comment> Stream is map to Flow
  98. Generated Client class CoroutineStub { } suspend fun getPlace(request: Location):

    Place fun recordTrip(requests: Flow<Location>): TripSummary fun listPlaces(request: Area): Flow<Place> fun chat(requests: Flow<Comment>): Flow<Comment>
  99. • Create Managed Channel • Specify server url, port •

    Create Client Stub Using Client
  100. Using Client val managedChannel = ManagedChannelBuilder .forAddress(host, port) .useTransportSecurity() .build()

  101. Using Client val managedChannel = ManagedChannelBuilder .forAddress(host, port) .useTransportSecurity() .build()

    Specify host and port
  102. Using Client val managedChannel = ManagedChannelBuilder .forAddress(host, port) .useTransportSecurity() for

    https
  103. Using Client val managedChannel = ManagedChannelBuilder .intercept(object : ClientInterceptor {

    fun interceptCall(method, callOptions, channel) { }) Intercept RPC Calls
  104. Using Client val managedChannel = ManagedChannelBuilder .forAddress(host, port) .useTransportSecurity() .build()

  105. Using Client val managedChannel = ManagedChannelBuilder .forAddress(host, port) .useTransportSecurity() .build()

    val client = CoroutineStub(managedChannel)
  106. View Model gRPC Client Stub

  107. Using Client class GrpcViewModel(val client: CoroutineStub): ViewModel() { }

  108. Unary RPC Call class CoroutineStub { } suspend fun getPlace(request:

    Location): Place
  109. Unary RPC Call fun getPlace(location: Location) { viewModelScope.launch { }

    }
  110. Unary RPC Call fun getPlace(location: Location) { viewModelScope.launch { val

    place = client.getPlace(location) } }
  111. Unary RPC Call fun getPlace(location: Location) { viewModelScope.launch { withContext(Dispatchers.IO)

    { val place = client.getPlace(location) } } }
  112. Server Streaming class CoroutineStub { } fun listPlaces(request: Area): Flow<Place>

  113. Server Streaming fun listPlaces(area: Area) { }

  114. Server Streaming fun listPlaces(area: Area) { viewModelScope.launch { } }

  115. Server Streaming fun listPlaces(area: Area) { viewModelScope.launch { val places:

    Flow<Place> = client.listPlaces(area) } }
  116. Server Streaming fun listPlaces(area: Area) { viewModelScope.launch { val places:

    Flow<Place> = client.listPlaces(area) places.collect { } } }
  117. Bidirectional RPC Call class CoroutineStub { } fun chat(requests: Flow<Comment>):

    Flow<Comment>
  118. Bidirectional RPC Call class CoroutineStub { } fun chat(requests: Flow<Comment>):

    Flow<Comment>
  119. Bidirectional RPC Call Client Stub Comments

  120. Bidirectional RPC Call State Flow Comments

  121. Bidirectional RPC Call State Flow Comments Comments Client Stub

  122. Using Client fun chat(comments: Flow<Comment>) { } Stream of comments

  123. Using Client fun chat(comments: Flow<Comment>) { viewModelScope.launch { } }

    } }
  124. Using Client fun chat(comments: Flow<Comment>) { viewModelScope.launch { client.chat(comments) }

    } } }
  125. Using Client fun chat(comments: Flow<Comment>) { viewModelScope.launch { client.chat(comments) .collect

    { } } } }
  126. Using Client class GrpcViewModel(val client: CoroutineStub): ViewModel() { fun getPlace(location:

    Location) fun listPlaces(area: Area): Flow<Place> fun chat(chat: Flow<Comment>) }
  127. gRPC Client Stub How does it use coroutines?

  128. Consumer Coroutine

  129. gRPC-java client Start Consumer Coroutine

  130. gRPC-java client Request Consumer Coroutine Producer Coroutine Response

  131. gRPC-java client Request Consumer Coroutine Producer Coroutine Response Channel (size

    = 1)
  132. gRPC-java client Request Consumer Coroutine Producer Coroutine Response Channel (size

    = 1)
  133. gRPC-java client Request Consumer Coroutine Producer Coroutine Response Channel (size

    = 1) Flow<Response>
  134. gRPC Client Stub How does it use coroutines?

  135. Android gRPC Client Stub Auth

  136. Auth Methods • JWT Token • Certificate Auth • HTTP

    Basic Auth
  137. Auth Client Server RPC Call

  138. Auth Client Server Metadata

  139. Auth Metadata headers = new Metadata();

  140. Auth Metadata headers = new Metadata(); headers.put(“auth_token","token");

  141. Auth val client = CoroutineStub(managedChannel)

  142. Auth val client = CoroutineStub(managedChannel) .withCallCredentials( . . . )

  143. withCallCredentials(object: CallCredentials { override fun applyRequestMetadata() { } } Auth

  144. withCallCredentials(object: CallCredentials { override fun applyRequestMetadata(applier: MetadataApplier) { } }

    Auth
  145. withCallCredentials(object: CallCredentials { override fun applyRequestMetadata(applier: MetadataApplier) { Metadata headers

    = new Metadata(); headers.put(“auth_token","token"); } } Auth
  146. withCallCredentials(object: CallCredentials { override fun applyRequestMetadata(applier: MetadataApplier) { Metadata headers

    = new Metadata(); headers.put(“auth_token","token"); applier.apply(headers); } } Auth
  147. Auth Client Server RPC Call

  148. Auth Client Server Metadata

  149. Errors Client Server RPC Call

  150. Errors Client Server Retry

  151. Enable Retry val managedChannel = ManagedChannelBuilder .forAddress(host, port) .useTransportSecurity() .enableRetry()

    .build()
  152. Client App gRPC Client Lib Server Application

  153. Client App gRPC Client Lib Server Application Make 
 gRPC

    Call Sends RPC
  154. Client App gRPC Client Lib Server Application Failure Make 


    gRPC Call Sends RPC
  155. Client App gRPC Client Lib Server Application Failure Make 


    gRPC Call Sends RPC Returns UNAVAILABLE
  156. Client App gRPC Client Lib Server Application Failure Make 


    gRPC Call Sends RPC Returns UNAVAILABLE Retried RPC
  157. Client App gRPC Client Lib Server Application Failure Make 


    gRPC Call Sends RPC Returns UNAVAILABLE Retried RPC Success Return OK Receive 
 data
  158. Enable Retry "retryPolicy": { "maxAttempts": 10, "initialBackoff": "5s", "maxBackoff": "1s",

    "backoffMultiplier": 2, "retryableStatusCodes": [ "UNAVAILABLE" ] }
  159. Hedging Client Server RPC Call(s)

  160. Client App gRPC Client Lib Server Application Make 
 gRPC

    Call Sends RPC
  161. Client App gRPC Client Lib Server Application Make 
 gRPC

    Call Sends RPC Return OK
  162. Client App gRPC Client Lib Server Application Make 
 gRPC

    Call Sends RPC Cancel
  163. Hedging Policy "hedgingPolicy": { "maxAttempts": 10, "hedgingDelay": “1.5s", "nonFatalStatusCodes": [

    "UNAVAILABLE", "INTERNAL", "ABORTED" ] }
  164. uw-labs/bloom-rpc Code ! Issues Pull Requests BloomRPC The missing GUI

    Client for GRPC services. release v1.5.2
  165. None
  166. gRPC https: / / codingwithmohit.com/grpc/grpc-kotlin-coroutines/

  167. Resources • gRPC with Kotlin Coroutines 
 
 https: /

    / codingwithmohit.com/grpc/grpc-kotlin-coroutines/ • Unit Testing Delays, Errors & Retries with Kotlin Flows 
 
 https: / / codingwithmohit.com/coroutines/unit-testing-delays- 
 errors-retries-with-kotlin-flows/ 
 

  168. Thank You! www.codingwithmohit.com @heyitsmohit