1 of 110

1

Marharyta Nedzelska

Software Engineer @ Wix.com

Building Microservices With Kotlin and gRPC

marharytan@wix.com twitter@jMargaritaN github.com/leveretka

2 of 110

2

Who am I?

Building Microservices with Kotlin and gRPC

Marharyta Nedzelska

  • Software Engineer @ Wix
  • KKUG & Kotlin Night Kyiv organizer
  • Devoxx UA program committee
  • Speaker at meetups and conferences
  • https://medium.com/@margoqueen95
  • @jMargaritaN twitter

3 of 110

3

One more thing you should know

Building Microservices with Kotlin and gRPC

I like boxing!

So think twice before asking tricky questions!

4 of 110

4

AGENDA

Why gRPC?

Protobuf

Implement Service

Error Handling

Testing

More libs for Kotlin

5 of 110

5

AGENDA

Why gRPC?

Protobuf

Implement Service

Error Handling

Testing

More libs for Kotlin

6 of 110

6

Who writes microservices today, please, raise your hands?

7 of 110

7

Microservices Rock!

  • Independent
  • Scalable
  • Mix tech stacks
  • Parallel development
  • etc...

Building Microservices with Kotlin and gRPC

8 of 110

8

9 of 110

9

The biggest issue in changing a monolith into microservices lies in changing the communication pattern.

Btw, who said this?

Darth Vader

10 of 110

10

11 of 110

11

The biggest issue in changing a monolith into microservices lies in changing the communication pattern.

Btw, who said this?

Darth Vader

12 of 110

12

The biggest issue in changing a monolith into microservices lies in changing the communication pattern.

Btw, who said this?

Martin Fowler

13 of 110

13

Who uses http 1.1 and REST today, please, raise your hands?

14 of 110

14

Clients

Servers

15 of 110

15

Why

gRPC?

01

16 of 110

16

Why gRPC?

  • Use HTTP/2
    • Single TCP connection
    • Bidirectional streaming
    • Flow control
  • Supports multiple languages
  • Binary, uses protobuf

Building Microservices with Kotlin and gRPC

17 of 110

17

1991

http 0.9

Http protocol evolution

Building Microservices with Kotlin and gRPC

1996

http 1.0

1997

http 1.1

18 of 110

18

Http protocol evolution

Building Microservices with Kotlin and gRPC

No progress here

2000

1999

1998

19 of 110

19

Http protocol evolution

Building Microservices with Kotlin and gRPC

And here

2003

2002

2001

20 of 110

20

Http protocol evolution

Building Microservices with Kotlin and gRPC

And still no progress...

2006

2005

2004

21 of 110

21

Http protocol evolution

Building Microservices with Kotlin and gRPC

Are they alive?

2009

2008

2007

22 of 110

22

Http protocol evolution

Building Microservices with Kotlin and gRPC

I guess no...

2012

2011

2010

23 of 110

23

Http protocol evolution

Building Microservices with Kotlin and gRPC

And suddenly!

2015

2014

2013

24 of 110

24

Http protocol evolution

Building Microservices with Kotlin and gRPC

2015

http/2

25 of 110

25

Why gRPC?

  • Use HTTP/2
    • Single TCP connection
    • Bidirectional streaming
    • Flow control
  • Supports multiple languages
  • Binary, uses protobuf

Building Microservices with Kotlin and gRPC

26 of 110

26

Why gRPC?

  • Use HTTP/2
    • Single TCP connection
    • Bidirectional streaming
    • Flow control
  • Supports multiple languages
  • Binary, uses protobuf

Building Microservices with Kotlin and gRPC

27 of 110

27

Why gRPC?

  • Use HTTP/2
    • Single TCP connection
    • Bidirectional streaming
    • Flow control
  • Supports multiple languages
  • Binary, uses protobuf

Building Microservices with Kotlin and gRPC

28 of 110

28

Why gRPC?

  • Use HTTP/2
    • Single TCP connection
    • Bidirectional streaming
    • Flow control
  • Supports multiple languages
  • Binary, uses protobuf

Building Microservices with Kotlin and gRPC

29 of 110

29

Why gRPC?

  • Use HTTP/2
    • Single TCP connection
    • Bidirectional streaming
    • Flow control
  • Supports multiple languages
  • Binary, uses protobuf

Building Microservices with Kotlin and gRPC

30 of 110

30

31 of 110

31

+

ScalaPB

32 of 110

32

?

33 of 110

33

AGENDA

Why gRPC?

Protobuf

Implement Service

Error Handling

Testing

More libs for Kotlin

34 of 110

34

Protocol

Buffers

02

35 of 110

35

Protocol buffers are Google’s language-neutral, platform-neutral, extensible mechanism for serializing structured data — think XML, but smaller, faster, and simpler.

https://developers.google.com/protocol-buffers/

36 of 110

36

Sample .proto file

Building Microservices with Kotlin and gRPC

syntax = "proto3";

package helloworld;

service Greeter {

rpc SayHello (HelloRequest) returns (HelloReply) {}

}

message HelloRequest {

string name = 1;

}

message HelloReply {

string message = 1;

}

37 of 110

37

Protobuf summary

  • Type Safety

Building Microservices with Kotlin and gRPC

38 of 110

38

Protobuf summary

  • Type Safety
  • No schema violations

Building Microservices with Kotlin and gRPC

39 of 110

39

Protobuf summary

  • Type Safety
  • No schema violations
  • Fast serialization/deserialization

Building Microservices with Kotlin and gRPC

40 of 110

40

Protobuf summary

  • Type Safety
  • No schema violations
  • Fast serialization/deserialization
  • Backward compatibility

Building Microservices with Kotlin and gRPC

41 of 110

41

Protobuf summary

  • Type Safety
  • No schema violations
  • Fast serialization/deserialization
  • Backward compatibility
  • Human readability

Building Microservices with Kotlin and gRPC

42 of 110

42

AGENDA

Why gRPC?

Protobuf

Implement Service

Interceptors

Flow Control

Error Handling

Testing

More libs for Kotlin

43 of 110

43

Implement Service

03

44 of 110

44

What does ‘gRPC’ stand for?

Riddle

45 of 110

45

“gRPC” means gRPC Remote Procedure Call

46 of 110

46

Building Microservices with Kotlin and gRPC

47 of 110

47

Let’s help gRPC team and think of other possible meanings!

48 of 110

48

Task for this session

  • Write voting chat application
  • Send funny ‘gRPC’ meanings
  • Vote for them
  • Tweet with #JFuture and #gRPC tags and like tweets
  • Greet winners at the end of our session!
  • Enjoy!

Building Microservices with Kotlin and gRPC

49 of 110

49

Application is here !

http://104.197.77.39:8080

50 of 110

50

Statistics stream

Messages stream

Building Microservices with Kotlin and gRPC

chat-service

stats-service

Join

Join

When user joins chat...

Messages stream

51 of 110

51

New gRPC meaning

Chat Message

Building Microservices with Kotlin and gRPC

chat-service

stats-service

Chat

When user chats...

Chat Message

Stats

52 of 110

52

Update votes

Building Microservices with Kotlin and gRPC

vote-service

stats-service

Vote

When user votes...

New vote

Stats

53 of 110

53

First iteration is done!

  • Single calls

Building Microservices with Kotlin and gRPC

54 of 110

54

First iteration is done!

  • Single calls
  • Server streaming

Building Microservices with Kotlin and gRPC

55 of 110

55

First iteration is done!

  • Single calls
  • Server streaming
  • Bidirectional streaming

Building Microservices with Kotlin and gRPC

56 of 110

56

First iteration is done!

  • Single calls
  • Server streaming
  • Bidirectional streaming
  • Simple stub

Building Microservices with Kotlin and gRPC

57 of 110

57

First iteration is done!

  • Single calls
  • Server streaming
  • Bidirectional streaming
  • Simple stub
  • Blocking stub

Building Microservices with Kotlin and gRPC

58 of 110

58

First iteration is done!

  • Single calls
  • Server streaming
  • Bidirectional streaming
  • Simple stub
  • Blocking stub
  • Future stub

Building Microservices with Kotlin and gRPC

59 of 110

59

AGENDA

Why gRPC?

Protobuf

Implement Service

Error Handling

Testing

More libs for Kotlin

60 of 110

60

Error Handling

04

61 of 110

61

All happy families are alike; each unhappy family is unhappy in its own way.

Btw, who said this?

Leo Tolstoy

62 of 110

62

Success

OK

Building Microservices with Kotlin and gRPC

63 of 110

63

Error

Building Microservices with Kotlin and gRPC

64 of 110

64

Error

Building Microservices with Kotlin and gRPC

65 of 110

65

Error

Building Microservices with Kotlin and gRPC

66 of 110

66

What about custom exceptions?

  • Server returns Status.Unknown if threw an exception

Building Microservices with Kotlin and gRPC

67 of 110

67

What about custom exceptions?

  • Server returns Status.Unknown if threw an exception
  • Return proper Status in Interceptor

Building Microservices with Kotlin and gRPC

68 of 110

68

Server interceptor

Use close method to change returned status

override fun <ReqT, RespT> interceptCall(call: ServerCall<ReqT, RespT>,

headers: Metadata, next: ServerCallHandler<ReqT, RespT>) : ServerCall.Listener<ReqT> {

val wrappedCall = object : ForwardingServerCall.SimpleForwardingServerCall<ReqT, RespT>(call) {

override fun close(status: Status, trailers: Metadata) {

var status = status

if (status.code == Status.Code.UNKNOWN && status.description == null

&& status.cause != null && throwables.contains(status.cause!!.javaClass)) {

val t = status.cause

status = Status.INTERNAL.withDescription(t!!.message)

.augmentDescription(stacktraceToString(t))

}

super.close(status, trailers)

}

}

return next.startCall(wrappedCall, headers)

}

69 of 110

69

Server interceptor

Use close method to change returned status

override fun <ReqT, RespT> interceptCall(call: ServerCall<ReqT, RespT>,

headers: Metadata, next: ServerCallHandler<ReqT, RespT>) : ServerCall.Listener<ReqT> {

val wrappedCall = object : ForwardingServerCall.SimpleForwardingServerCall<ReqT, RespT>(call) {

override fun close(status: Status, trailers: Metadata) {

var status = status

if (status.code == Status.Code.UNKNOWN && status.description == null

&& status.cause != null && throwables.contains(status.cause!!.javaClass)) {

val t = status.cause

status = Status.INTERNAL.withDescription(t!!.message)

.augmentDescription(stacktraceToString(t))

}

super.close(status, trailers)

}

}

return next.startCall(wrappedCall, headers)

}

70 of 110

70

What about custom exceptions?

  • Server returns Status.Unknown if threw an exception
  • Return proper Status in Interceptor
  • Handle status codes in client

Building Microservices with Kotlin and gRPC

71 of 110

71

Client

Catch Status Runtime Exception

try {

stub.doSth(request)

} catch (e: StatusRuntimeException) {

logger.log(Level.SEVERE, e.message, e)

}

72 of 110

72

AGENDA

Why gRPC?

Protobuf

Implement Service

Error Handling

Testing

More libs for Kotlin

73 of 110

73

Testing

05

74 of 110

74

75 of 110

75

Unit testing

  • Use InProcessServerBuilder
  • Use InProcessChannelBuilder

Building Microservices with Kotlin and gRPC

76 of 110

76

Let’s test chat method on server

lateinit var server: Server

lateinit var inProcessChannel: ManagedChannel

@Before

@Throws(Exception::class)

fun setUp() {

val serverName = InProcessServerBuilder.generateName()

server = InProcessServerBuilder.forName(serverName).directExecutor()

.addService(ManualFlowChatServiceImpl())

.build().start()

inProcessChannel = InProcessChannelBuilder.forName(serverName).directExecutor().build()

}

Building Microservices with Kotlin and gRPC

77 of 110

77

Let’s test chat method on server

lateinit var server: Server

lateinit var inProcessChannel: ManagedChannel

@Before

@Throws(Exception::class)

fun setUp() {

val serverName = InProcessServerBuilder.generateName()

server = InProcessServerBuilder.forName(serverName).directExecutor()

.addService(ChatServiceImpl())

.build().start()

inProcessChannel = InProcessChannelBuilder.forName(serverName).directExecutor().build()

}

Building Microservices with Kotlin and gRPC

78 of 110

78

Unit testing

  • Use InProcessServerBuilder
  • Use InProcessChannelBuilder
  • Do not forget to clean up

Building Microservices with Kotlin and gRPC

79 of 110

79

Let’s test chat method on server

@RunWith(JUnit4::class)

class ChatServiceTest {

lateinit var server: Server

lateinit var inProcessChannel: ManagedChannel

...

@After

fun tearDown() {

inProcessChannel.shutdown()

server.shutdown()

}

...

}

Building Microservices with Kotlin and gRPC

80 of 110

80

Unit testing

  • Use InProcessServerBuilder
  • Use InProcessChannelBuilder
  • Do not forget to clean up
  • Write tests

Building Microservices with Kotlin and gRPC

81 of 110

81

Let’s test chat method on server

@Test

fun chatTest() {

val stub = ChatServiceGrpc.newStub(inProcessChannel)

val responseObserver: StreamObserver<ChatProto.ChatMessage> = mock { }

val requestObserver = stub.chat(responseObserver)

val chatMessage = ChatMessage.newBuilder().setFrom("Margo").setContent("Hello!").build()

val chatMessageCaptor: ArgumentCaptor<ChatProto.ChatMessage> =

ArgumentCaptor.forClass(ChatMessage::class.java)

requestObserver.onNext(chatMessage)

chatMessageCaptor.run {

verify(responseObserver).onNext(capture())

assertEquals("Margo", value.from)

assertEquals("Hello!", value.content)

}

}

Building Microservices with Kotlin and gRPC

82 of 110

82

Let’s test chat method on server

@Test

fun chatTest() {

val stub = ChatServiceGrpc.newStub(inProcessChannel)

val responseObserver: StreamObserver<ChatProto.ChatMessage> = mock { }

val requestObserver = stub.chat(responseObserver)

val chatMessage = ChatMessage.newBuilder().setFrom("Margo").setContent("Hello!").build()

val chatMessageCaptor: ArgumentCaptor<ChatProto.ChatMessage> =

ArgumentCaptor.forClass(ChatMessage::class.java)

requestObserver.onNext(chatMessage)

chatMessageCaptor.run {

verify(responseObserver).onNext(capture())

assertEquals("Margo", value.from)

assertEquals("Hello!", value.content)

}

}

Building Microservices with Kotlin and gRPC

83 of 110

83

What about integration

and e2e test?

84 of 110

84

85 of 110

85

If you made a death star

86 of 110

86

You should provide staff to test it!

87 of 110

87

Testing summary

  • Write unit tests

Building Microservices with Kotlin and gRPC

88 of 110

88

Testing summary

  • Write unit tests
  • Deal with streaming easily

Building Microservices with Kotlin and gRPC

89 of 110

89

Testing summary

  • Write unit tests
  • Deal with streaming easily
  • No unified approach or lib for IT and e2e

Building Microservices with Kotlin and gRPC

90 of 110

90

Testing summary

  • Write unit tests
  • Deal with streaming easily
  • No unified approach or lib for IT and e2e
  • At Wix testkits approach works for us

Building Microservices with Kotlin and gRPC

91 of 110

91

AGENDA

Why gRPC?

Protobuf

Implement Service

Error Handling

Testing

More libs for Kotlin

92 of 110

92

More libs for

Kotlin

06

93 of 110

93

Building Microservices with Kotlin and gRPC

94 of 110

94

Building Microservices with Kotlin and gRPC

95 of 110

95

Expectation

Building Microservices with Kotlin and gRPC

96 of 110

96

Reality

Building Microservices with Kotlin and gRPC

97 of 110

97

https://github.com/rouzwawi/grpc-kotlin.git

98 of 110

98

https://github.com/rouzwawi/grpc-kotlin.git

99 of 110

99

https://github.com/rouzwawi/grpc-kotlin.git

100 of 110

100

https://github.com/marcoferrer/kroto-plus.git

101 of 110

101

Examples

//Kroto+ Overloadedval response = serviceStub.myRpcMethod {� id = 100� name = "some name"� }

Building Microservices with Kotlin and gRPC

102 of 110

102

Examples

suspend fun findStrongestAttack(): StandProto.Attack {� val standService = StandServiceGrpc.newStub(managedChannel)� val characterService = CharacterServiceGrpc.newStub(managedChannel)� val deferredStands = characterService.getAllCharactersStream()� .map { character ->� async { standService.getStandByCharacter(character) }� }.toList()� val strongestAttack = deferredStands� .flatMap { it.await().attacksList }� .maxBy { it.damage } � return strongestAttack ?: StandProto.Attack.getDefaultInstance()}

Building Microservices with Kotlin and gRPC

103 of 110

103

Examples

suspend fun findStrongestAttack(): StandProto.Attack {� val standService = StandServiceGrpc.newStub(managedChannel)� val characterService = CharacterServiceGrpc.newStub(managedChannel)� val deferredStands = characterService.getAllCharactersStream()� .map { character ->� async { standService.getStandByCharacter(character) }� }.toList()� val strongestAttack = deferredStands� .flatMap { it.await().attacksList }� .maxBy { it.damage } � return strongestAttack ?: StandProto.Attack.getDefaultInstance()}

Building Microservices with Kotlin and gRPC

104 of 110

104

Examples

val attack = Attack {� name = "ORA ORA ORA"� damage = 100� range = StandProto.Attack.Range.CLOSE}�//Copy extensions are also generatedval newAttack = attack.copy { damage = 200 } ��//As well as plus operator extensions val mergedAttack = attack + Attack { name = "Sunlight Yellow Overdrive" }

Building Microservices with Kotlin and gRPC

105 of 110

105

One day we’ll have proper kotlin support

106 of 110

106

Takeaways

  • Use gRPC for effective communications
  • gRPC + Kotlin can be used today
  • Waiting for proper coroutines support
  • Feel free to contribute :)

INSERT YOUR�TOPIC NAME

107 of 110

107

My gRPC Kotlin Sandbox

https://github.com/leveretka/grpc-chat.git

108 of 110

108

Time to define winner!

109 of 110

109

Thank You

marharytan@wix.com twitter@jMargaritaN github.com/leveretka

110 of 110

110

Q&A

marharytan@wix.com twitter@jMargaritaN github.com/leveretka