Server-side Kotlin with Coroutines · •async/await asyncfun loadMargin(account: Account): Task...

126
Server-side Kotlin with Coroutines Roman Elizarov relizarov

Transcript of Server-side Kotlin with Coroutines · •async/await asyncfun loadMargin(account: Account): Task...

Page 1: Server-side Kotlin with Coroutines · •async/await asyncfun loadMargin(account: Account): Task But how? •Callbacks •Futures/Promises/Reactive •async/await ...

Server-side Kotlinwith Coroutines

Roman Elizarovrelizarov

Page 2: Server-side Kotlin with Coroutines · •async/await asyncfun loadMargin(account: Account): Task But how? •Callbacks •Futures/Promises/Reactive •async/await ...

Speaker: Roman Elizarov

• Professional developer since 2000• Previously developed high-perf trading software

@ Devexperts• Teach concurrent & distributed programming

@ St. Petersburg ITMO University• Chief judge

@ Northern Eurasia Contest / ICPC • Now team lead in Kotlin Libraries

@ JetBrainselizarov @relizarov

Page 3: Server-side Kotlin with Coroutines · •async/await asyncfun loadMargin(account: Account): Task But how? •Callbacks •Futures/Promises/Reactive •async/await ...

Kotlin – Programming Language for

Page 4: Server-side Kotlin with Coroutines · •async/await asyncfun loadMargin(account: Account): Task But how? •Callbacks •Futures/Promises/Reactive •async/await ...

Kotlin – Programming Language for

This talkServer-side

Page 5: Server-side Kotlin with Coroutines · •async/await asyncfun loadMargin(account: Account): Task But how? •Callbacks •Futures/Promises/Reactive •async/await ...

Backend evolutionStarting with “good old days”

Page 6: Server-side Kotlin with Coroutines · •async/await asyncfun loadMargin(account: Account): Task But how? •Callbacks •Futures/Promises/Reactive •async/await ...

ET 1

ET 2

ET N

Executor Threads

DB

Old-school client-server monolith

Clients

Page 7: Server-side Kotlin with Coroutines · •async/await asyncfun loadMargin(account: Account): Task But how? •Callbacks •Futures/Promises/Reactive •async/await ...

ET 1

ET 2

ET N

Executor Threads

DB

Incoming request

Clients

Page 8: Server-side Kotlin with Coroutines · •async/await asyncfun loadMargin(account: Account): Task But how? •Callbacks •Futures/Promises/Reactive •async/await ...

ET 1

ET 2

ET N

Executor Threads

DB

Blocks tread

!

Clients

Page 9: Server-side Kotlin with Coroutines · •async/await asyncfun loadMargin(account: Account): Task But how? •Callbacks •Futures/Promises/Reactive •async/await ...

ET 1

ET 2

ET N

Executor Threads

DB

Sizing threads – easy

Clients

N = number of DB connections

Page 10: Server-side Kotlin with Coroutines · •async/await asyncfun loadMargin(account: Account): Task But how? •Callbacks •Futures/Promises/Reactive •async/await ...

Services

Page 11: Server-side Kotlin with Coroutines · •async/await asyncfun loadMargin(account: Account): Task But how? •Callbacks •Futures/Promises/Reactive •async/await ...

ET 1

ET 2

ET N

Executor Threads

DB

Old-school client-server monolith

Clients

Page 12: Server-side Kotlin with Coroutines · •async/await asyncfun loadMargin(account: Account): Task But how? •Callbacks •Futures/Promises/Reactive •async/await ...

ET 1

ET 2

ET N

Executor Threads

DB

Now with Services

Service

Clients

Page 13: Server-side Kotlin with Coroutines · •async/await asyncfun loadMargin(account: Account): Task But how? •Callbacks •Futures/Promises/Reactive •async/await ...

ET 1

ET 2

ET N

Executor Threads

Services everywhere

Service K

Service 1

Service 2Clients

Page 14: Server-side Kotlin with Coroutines · •async/await asyncfun loadMargin(account: Account): Task But how? •Callbacks •Futures/Promises/Reactive •async/await ...

ET 1

ET 2

ET N

Executor Threads

Sizing threads – not easy

N = ?????

Service K

Service 1

Service 2Clients

Page 15: Server-side Kotlin with Coroutines · •async/await asyncfun loadMargin(account: Account): Task But how? •Callbacks •Futures/Promises/Reactive •async/await ...

Complex business logic

fun placeOrder(order: Order): Response {…

}

Page 16: Server-side Kotlin with Coroutines · •async/await asyncfun loadMargin(account: Account): Task But how? •Callbacks •Futures/Promises/Reactive •async/await ...

Complex business logic

fun placeOrder(order: Order): Response {val account = accountService.loadAccout(order.accountId)…

}

Page 17: Server-side Kotlin with Coroutines · •async/await asyncfun loadMargin(account: Account): Task But how? •Callbacks •Futures/Promises/Reactive •async/await ...

Complex business logic

fun placeOrder(order: Order): Response {val account = accountService.loadAccout(order.accountId)val margin = if (account.isOptionsAccount)…

}

Page 18: Server-side Kotlin with Coroutines · •async/await asyncfun loadMargin(account: Account): Task But how? •Callbacks •Futures/Promises/Reactive •async/await ...

Complex business logic

fun placeOrder(order: Order): Response {val account = accountService.loadAccout(order.accountId)val margin = if (account.isOptionsAccount) {

marginService.loadMargin(account)} else {

defaultMargin}…

}

Page 19: Server-side Kotlin with Coroutines · •async/await asyncfun loadMargin(account: Account): Task But how? •Callbacks •Futures/Promises/Reactive •async/await ...

Complex business logic

fun placeOrder(order: Order): Response {val account = accountService.loadAccout(order.accountId)val margin = if (account.isOptionsAccount) {

marginService.loadMargin(account)} else {

defaultMargin}return validateOrder(order, margin)

}

Page 20: Server-side Kotlin with Coroutines · •async/await asyncfun loadMargin(account: Account): Task But how? •Callbacks •Futures/Promises/Reactive •async/await ...

Complex business logic

fun placeOrder(order: Order): Response {val account = accountService.loadAccout(order.accountId)val margin = if (account.isOptionsAccount) {

marginService.loadMargin(account)} else {

defaultMargin}return validateOrder(order, margin)

}

Page 21: Server-side Kotlin with Coroutines · •async/await asyncfun loadMargin(account: Account): Task But how? •Callbacks •Futures/Promises/Reactive •async/await ...

What if a service is slow?

fun placeOrder(order: Order): Response {val account = accountService.loadAccout(order.accountId)val margin = if (account.isOptionsAccount) {

marginService.loadMargin(account)} else {

defaultMargin}return validateOrder(order, margin)

}

!

Page 22: Server-side Kotlin with Coroutines · •async/await asyncfun loadMargin(account: Account): Task But how? •Callbacks •Futures/Promises/Reactive •async/await ...

ET 2

ET N

Executor Threads

Clients

Blocks threads

Service K

Service 1

Service 2

ET 1!

"

Page 23: Server-side Kotlin with Coroutines · •async/await asyncfun loadMargin(account: Account): Task But how? •Callbacks •Futures/Promises/Reactive •async/await ...

ET 2

ET N

Executor Threads

Clients

Blocks threads

Service K

Service 1

Service 2

ET 1!

"!

Page 24: Server-side Kotlin with Coroutines · •async/await asyncfun loadMargin(account: Account): Task But how? •Callbacks •Futures/Promises/Reactive •async/await ...

ET 2

ET N

Executor Threads

Clients

Blocks threads

Service K

Service 1

Service 2

ET 1!

"!

!

Page 25: Server-side Kotlin with Coroutines · •async/await asyncfun loadMargin(account: Account): Task But how? •Callbacks •Futures/Promises/Reactive •async/await ...

Code that waits

Page 26: Server-side Kotlin with Coroutines · •async/await asyncfun loadMargin(account: Account): Task But how? •Callbacks •Futures/Promises/Reactive •async/await ...

Asynchronous programmingWriting code that waits

Page 27: Server-side Kotlin with Coroutines · •async/await asyncfun loadMargin(account: Account): Task But how? •Callbacks •Futures/Promises/Reactive •async/await ...

ET 2

ET N

Executor Threads

Clients

Instead of blocking…

Service K

Service 1

Service 2

ET 1!

"

Page 28: Server-side Kotlin with Coroutines · •async/await asyncfun loadMargin(account: Account): Task But how? •Callbacks •Futures/Promises/Reactive •async/await ...

ET 2

ET N

Executor Threads

Release the thread

Service K

Service 1

Service 2

ET 1

!Clients

Page 29: Server-side Kotlin with Coroutines · •async/await asyncfun loadMargin(account: Account): Task But how? •Callbacks •Futures/Promises/Reactive •async/await ...

ClientsET 2

ET N

Executor Threads

Resume operation later

Service K

Service 1

Service 2

ET 1

!

Page 30: Server-side Kotlin with Coroutines · •async/await asyncfun loadMargin(account: Account): Task But how? •Callbacks •Futures/Promises/Reactive •async/await ...

But how?

fun loadMargin(account: Account): Margin

Page 31: Server-side Kotlin with Coroutines · •async/await asyncfun loadMargin(account: Account): Task But how? •Callbacks •Futures/Promises/Reactive •async/await ...

But how?

•Callbacks

fun loadMargin(account: Account, callback: (Margin) -> Unit)

Page 32: Server-side Kotlin with Coroutines · •async/await asyncfun loadMargin(account: Account): Task But how? •Callbacks •Futures/Promises/Reactive •async/await ...

But how?

•Callbacks•Futures/Promises

fun loadMargin(account: Account): Future<Margin>

Page 33: Server-side Kotlin with Coroutines · •async/await asyncfun loadMargin(account: Account): Task But how? •Callbacks •Futures/Promises/Reactive •async/await ...

But how?

•Callbacks•Futures/Promises/Reactive

fun loadMargin(account: Account): Mono<Margin>

Page 34: Server-side Kotlin with Coroutines · •async/await asyncfun loadMargin(account: Account): Task But how? •Callbacks •Futures/Promises/Reactive •async/await ...

But how?

•Callbacks•Futures/Promises/Reactive•async/await

async fun loadMargin(account: Account): Task<Margin>

Page 35: Server-side Kotlin with Coroutines · •async/await asyncfun loadMargin(account: Account): Task But how? •Callbacks •Futures/Promises/Reactive •async/await ...

But how?

•Callbacks•Futures/Promises/Reactive•async/await•Kotlin Coroutines

suspend fun loadMargin(account: Account): Margin

Page 36: Server-side Kotlin with Coroutines · •async/await asyncfun loadMargin(account: Account): Task But how? •Callbacks •Futures/Promises/Reactive •async/await ...

Learn more

KotlinConf (San Francisco) 2017 GOTO Copenhagen 2018

Page 37: Server-side Kotlin with Coroutines · •async/await asyncfun loadMargin(account: Account): Task But how? •Callbacks •Futures/Promises/Reactive •async/await ...

Suspend behind the scenes

suspend fun loadMargin(account: Account): Margin

Page 38: Server-side Kotlin with Coroutines · •async/await asyncfun loadMargin(account: Account): Task But how? •Callbacks •Futures/Promises/Reactive •async/await ...

Suspend behind the scenes

suspend fun loadMargin(account: Account): Margin

fun loadMargin(account: Account, cont: Continuation<Margin>)

But why callback and not future?

Page 39: Server-side Kotlin with Coroutines · •async/await asyncfun loadMargin(account: Account): Task But how? •Callbacks •Futures/Promises/Reactive •async/await ...

Performance!

•Future is a synchronization primitive•Callback is a lower-level primitive• Integration with async IO libraries is easy

Page 40: Server-side Kotlin with Coroutines · •async/await asyncfun loadMargin(account: Account): Task But how? •Callbacks •Futures/Promises/Reactive •async/await ...

Integration

suspend fun loadMargin(account: Account): Margin

Page 41: Server-side Kotlin with Coroutines · •async/await asyncfun loadMargin(account: Account): Task But how? •Callbacks •Futures/Promises/Reactive •async/await ...

Integration

suspend fun loadMargin(account: Account): Margin =suspendCoroutine { cont ->

// install callback & use cont to resume}

Page 42: Server-side Kotlin with Coroutines · •async/await asyncfun loadMargin(account: Account): Task But how? •Callbacks •Futures/Promises/Reactive •async/await ...

Integration at scaleGoing beyond slide-ware

Page 43: Server-side Kotlin with Coroutines · •async/await asyncfun loadMargin(account: Account): Task But how? •Callbacks •Futures/Promises/Reactive •async/await ...

ET 2

ET N

Executor Threads

Clients

Release thread?

Service K

Service 1

Service 2

ET 1!

"

Page 44: Server-side Kotlin with Coroutines · •async/await asyncfun loadMargin(account: Account): Task But how? •Callbacks •Futures/Promises/Reactive •async/await ...

Blocking server

fun placeOrder(order: Order): Response {// must return response

}

Page 45: Server-side Kotlin with Coroutines · •async/await asyncfun loadMargin(account: Account): Task But how? •Callbacks •Futures/Promises/Reactive •async/await ...

Asynchronous server

fun placeOrder(order: Order): Mono<Response> {// may return without response

}

Page 46: Server-side Kotlin with Coroutines · •async/await asyncfun loadMargin(account: Account): Task But how? •Callbacks •Futures/Promises/Reactive •async/await ...

Convenient?

fun placeOrder(order: Order): Mono<Response> {// response from placed order cachereturn Mono.just(response)

}

Page 47: Server-side Kotlin with Coroutines · •async/await asyncfun loadMargin(account: Account): Task But how? •Callbacks •Futures/Promises/Reactive •async/await ...

Server integrated with coroutines

suspend fun placeOrder(order: Order): Response {// response from placed order cachereturn response

}

Page 48: Server-side Kotlin with Coroutines · •async/await asyncfun loadMargin(account: Account): Task But how? •Callbacks •Futures/Promises/Reactive •async/await ...

Server not integrated with coroutines

fun placeOrder(order: Order) = GlobalScope.mono {// response from placed order cachereturn@mono response

}Coroutine builder

Page 49: Server-side Kotlin with Coroutines · •async/await asyncfun loadMargin(account: Account): Task But how? •Callbacks •Futures/Promises/Reactive •async/await ...

The server shall support asynchrony is some way

Page 50: Server-side Kotlin with Coroutines · •async/await asyncfun loadMargin(account: Account): Task But how? •Callbacks •Futures/Promises/Reactive •async/await ...

Suspend

suspend fun placeOrder(order: Order): Response {val account = accountService.loadAccout(order.accountId)val margin = if (account.isOptionsAccount) {

marginService.loadMargin(account)} else {

defaultMargin}return validateOrder(order, margin)

}

Page 51: Server-side Kotlin with Coroutines · •async/await asyncfun loadMargin(account: Account): Task But how? •Callbacks •Futures/Promises/Reactive •async/await ...

Suspend

suspend fun placeOrder(order: Order): Response {val account = accountService.loadAccout(order.accountId)val margin = if (account.isOptionsAccount) {

marginService.loadMargin(account)} else {

defaultMargin}return validateOrder(order, margin)

}

Invoke suspending funs

Page 52: Server-side Kotlin with Coroutines · •async/await asyncfun loadMargin(account: Account): Task But how? •Callbacks •Futures/Promises/Reactive •async/await ...

Suspend is convenient

suspend fun placeOrder(order: Order): Response {val account = accountService.loadAccout(order.accountId)val margin = if (account.isOptionsAccount) {

marginService.loadMargin(account)} else {

defaultMargin}return validateOrder(order, margin)

}

Invoke suspending funs

Write regular code!

Page 53: Server-side Kotlin with Coroutines · •async/await asyncfun loadMargin(account: Account): Task But how? •Callbacks •Futures/Promises/Reactive •async/await ...

Suspend is efficient

suspend fun placeOrder(order: Order): Response {val account = accountService.loadAccount(order.accountId)val margin = marginService.loadMargin(account)return validateOrder(order, margin)

}

One object allocated

Page 54: Server-side Kotlin with Coroutines · •async/await asyncfun loadMargin(account: Account): Task But how? •Callbacks •Futures/Promises/Reactive •async/await ...

Futures/Promises/Reactive – less efficient

fun placeOrder(order: Order): Mono<Response> =accountService.loadAccountAsync(order.accountId)

.flatMap { account -> marginService.loadMargin(account) }

.map { margin -> validateOrder(order, margin) }

Lambda allocated*

Future allocatedLambda allocated

Future allocated

Page 55: Server-side Kotlin with Coroutines · •async/await asyncfun loadMargin(account: Account): Task But how? •Callbacks •Futures/Promises/Reactive •async/await ...

Let’s go deeper

fun placeOrder(params: Params): Mono<Response> {// check pre-conditionsreturn actuallyPlaceOrder(order)

}

fun actuallyPlaceOrder(order: Order): Mono<Response>

Page 56: Server-side Kotlin with Coroutines · •async/await asyncfun loadMargin(account: Account): Task But how? •Callbacks •Futures/Promises/Reactive •async/await ...

Let’s go deeper (with coroutines)

suspend fun placeOrder(params: Params): Response {// check pre-conditionsreturn actuallyPlaceOrder(order)

}

suspend fun actuallyPlaceOrder(params: Params): Response

Tail call optimization

Tail call

Page 57: Server-side Kotlin with Coroutines · •async/await asyncfun loadMargin(account: Account): Task But how? •Callbacks •Futures/Promises/Reactive •async/await ...

Call stack with coroutines

Coroutine Builder

placeOrder

actuallyPlaceOrder

moreLogic

marginService.loadMargin

suspendCoroutine

Page 58: Server-side Kotlin with Coroutines · •async/await asyncfun loadMargin(account: Account): Task But how? •Callbacks •Futures/Promises/Reactive •async/await ...

Call stack with coroutines

Coroutine Builder

placeOrder

actuallyPlaceOrder

moreLogic

marginService.loadMargin

suspendCoroutine

unw

ind

Continuation in heap

Page 59: Server-side Kotlin with Coroutines · •async/await asyncfun loadMargin(account: Account): Task But how? •Callbacks •Futures/Promises/Reactive •async/await ...

Scaling with coroutinesWith thread pools

Page 60: Server-side Kotlin with Coroutines · •async/await asyncfun loadMargin(account: Account): Task But how? •Callbacks •Futures/Promises/Reactive •async/await ...

ET 2

ET N

Executor Threads

Clients

Thread pools

ET 1

Page 61: Server-side Kotlin with Coroutines · •async/await asyncfun loadMargin(account: Account): Task But how? •Callbacks •Futures/Promises/Reactive •async/await ...

ET 2

ET N

Executor Threads

Clients

Thread pools

ET 1

Service 1 Threads

ST 2

ST M1

S1 1

N = number of CPU cores M1 = depends

Page 62: Server-side Kotlin with Coroutines · •async/await asyncfun loadMargin(account: Account): Task But how? •Callbacks •Futures/Promises/Reactive •async/await ...

IO-bound (blocking)

fun loadAccount(order: Order): Account {// some blocking code here....

}

Page 63: Server-side Kotlin with Coroutines · •async/await asyncfun loadMargin(account: Account): Task But how? •Callbacks •Futures/Promises/Reactive •async/await ...

IO-bound

suspend fun loadAccount(order: Order): Account {// some blocking code here....

}

Page 64: Server-side Kotlin with Coroutines · •async/await asyncfun loadMargin(account: Account): Task But how? •Callbacks •Futures/Promises/Reactive •async/await ...

IO-bound withContext

suspend fun loadAccount(order: Order): Account = withContext(dispatcher) {

// some blocking code here....}

Page 65: Server-side Kotlin with Coroutines · •async/await asyncfun loadMargin(account: Account): Task But how? •Callbacks •Futures/Promises/Reactive •async/await ...

IO-bound withContext

suspend fun loadAccount(order: Order): Account = withContext(dispatcher) {

// some blocking code here....}

val dispatcher =Executors.newFixedThreadPool(M2).asCoroutineDispatcher()

Page 66: Server-side Kotlin with Coroutines · •async/await asyncfun loadMargin(account: Account): Task But how? •Callbacks •Futures/Promises/Reactive •async/await ...

CPU-bound code

fun validateOrder(order: Order, margin: Margin): Response {// perform CPU-consuming computation

}

Page 67: Server-side Kotlin with Coroutines · •async/await asyncfun loadMargin(account: Account): Task But how? •Callbacks •Futures/Promises/Reactive •async/await ...

CPU-bound code

suspend fun validateOrder(order: Order, margin: Margin): Response =withContext(compute) {

// perform CPU-consuming computation}

val compute = Executors.newFixedThreadPool(M3).asCoroutineDispatcher()

Page 68: Server-side Kotlin with Coroutines · •async/await asyncfun loadMargin(account: Account): Task But how? •Callbacks •Futures/Promises/Reactive •async/await ...

ET 2

ET N

Executor Threads

Clients

Fine-grained control and encapsulation

ET 1

Service 1 Threads

S1 1ST M1

Service 2 Threads

S1 1ST M2

Service 3 Threads

S1 1ST M3

Async

IO-bound

CPU-boundNever blocked

Page 69: Server-side Kotlin with Coroutines · •async/await asyncfun loadMargin(account: Account): Task But how? •Callbacks •Futures/Promises/Reactive •async/await ...

But there’s more!

Page 70: Server-side Kotlin with Coroutines · •async/await asyncfun loadMargin(account: Account): Task But how? •Callbacks •Futures/Promises/Reactive •async/await ...

Cancellation

Page 71: Server-side Kotlin with Coroutines · •async/await asyncfun loadMargin(account: Account): Task But how? •Callbacks •Futures/Promises/Reactive •async/await ...

withTimeout

suspend fun placeOrder(order: Order): Response =withTimeout(1000) {

// code beforeloadMargin(account)// code after

}

Page 72: Server-side Kotlin with Coroutines · •async/await asyncfun loadMargin(account: Account): Task But how? •Callbacks •Futures/Promises/Reactive •async/await ...

withTimeout propagation

suspend fun placeOrder(order: Order): Response =withTimeout(1000) {

// code beforeloadMargin(account)// code after

}

suspend fun loadMargin(account: Account): Margin =suspendCoroutine { cont ->

// install callback & use cont to resume}

Page 73: Server-side Kotlin with Coroutines · •async/await asyncfun loadMargin(account: Account): Task But how? •Callbacks •Futures/Promises/Reactive •async/await ...

withTimeout propagation

suspend fun placeOrder(order: Order): Response =withTimeout(1000) {

// code beforeloadMargin(account)// code after

}

suspend fun loadMargin(account: Account): Margin =suspendCancellableCoroutine { cont ->

// install callback & use cont to resume}

Page 74: Server-side Kotlin with Coroutines · •async/await asyncfun loadMargin(account: Account): Task But how? •Callbacks •Futures/Promises/Reactive •async/await ...

withTimeout propagation

suspend fun placeOrder(order: Order): Response =withTimeout(1000) {

// code beforeloadMargin(account)// code after

}

suspend fun loadMargin(account: Account): Margin =suspendCancellableCoroutine { cont ->

// install callback & use cont to resumecont.invokeOnCancellation { … }

}

Page 75: Server-side Kotlin with Coroutines · •async/await asyncfun loadMargin(account: Account): Task But how? •Callbacks •Futures/Promises/Reactive •async/await ...

ConcurrencyMultiple things at the same time

Page 76: Server-side Kotlin with Coroutines · •async/await asyncfun loadMargin(account: Account): Task But how? •Callbacks •Futures/Promises/Reactive •async/await ...

Example

fun placeOrder(order: Order): Response {val account = accountService.loadAccount(order)val margin = marginService.loadMargin(order)return validateOrder(order, account, margin)

}

Page 77: Server-side Kotlin with Coroutines · •async/await asyncfun loadMargin(account: Account): Task But how? •Callbacks •Futures/Promises/Reactive •async/await ...

Example

fun placeOrder(order: Order): Response {val account = accountService.loadAccount(order)val margin = marginService.loadMargin(order)return validateOrder(order, account, margin)

}

No data dependencies

Page 78: Server-side Kotlin with Coroutines · •async/await asyncfun loadMargin(account: Account): Task But how? •Callbacks •Futures/Promises/Reactive •async/await ...

Concurrency with async (futures)

fun placeOrder(order: Order): Response {val account = accountService.loadAccountAsync(order)val margin = marginService.loadMarginAsync(order)return validateOrder(order, account.await(), margin.await())

}

Page 79: Server-side Kotlin with Coroutines · •async/await asyncfun loadMargin(account: Account): Task But how? •Callbacks •Futures/Promises/Reactive •async/await ...

Concurrency with async (futures)

fun placeOrder(order: Order): Response {val account = accountService.loadAccountAsync(order)val margin = marginService.loadMarginAsync(order)return validateOrder(order, account.await(), margin.await())

}

Page 80: Server-side Kotlin with Coroutines · •async/await asyncfun loadMargin(account: Account): Task But how? •Callbacks •Futures/Promises/Reactive •async/await ...

Concurrency with async (futures)

fun placeOrder(order: Order): Response {val account = accountService.loadAccountAsync(order)val margin = marginService.loadMarginAsync(order)return validateOrder(order, account.await(), margin.await())

}

Fails?

Page 81: Server-side Kotlin with Coroutines · •async/await asyncfun loadMargin(account: Account): Task But how? •Callbacks •Futures/Promises/Reactive •async/await ...

Concurrency with async (futures)

fun placeOrder(order: Order): Response {val account = accountService.loadAccountAsync(order)val margin = marginService.loadMarginAsync(order)return validateOrder(order, account.await(), margin.await())

}

Fails? Leaks!

Page 82: Server-side Kotlin with Coroutines · •async/await asyncfun loadMargin(account: Account): Task But how? •Callbacks •Futures/Promises/Reactive •async/await ...

Structured concurrency

Page 83: Server-side Kotlin with Coroutines · •async/await asyncfun loadMargin(account: Account): Task But how? •Callbacks •Futures/Promises/Reactive •async/await ...

Concurrency with coroutines

suspend fun placeOrder(order: Order): Response =coroutineScope {

val account = async { accountService.loadAccount(order) }val margin = async { marginService.loadMargin(order) }validateOrder(order, account.await(), margin.await())

}

Page 84: Server-side Kotlin with Coroutines · •async/await asyncfun loadMargin(account: Account): Task But how? •Callbacks •Futures/Promises/Reactive •async/await ...

Concurrency with coroutines

suspend fun placeOrder(order: Order): Response =coroutineScope {

val account = async { accountService.loadAccount(order) }val margin = async { marginService.loadMargin(order) }validateOrder(order, account.await(), margin.await())

}

Page 85: Server-side Kotlin with Coroutines · •async/await asyncfun loadMargin(account: Account): Task But how? •Callbacks •Futures/Promises/Reactive •async/await ...

Concurrency with coroutines

suspend fun placeOrder(order: Order): Response =coroutineScope {

val account = async { accountService.loadAccount(order) }val margin = async { marginService.loadMargin(order) }validateOrder(order, account.await(), margin.await())

}

Page 86: Server-side Kotlin with Coroutines · •async/await asyncfun loadMargin(account: Account): Task But how? •Callbacks •Futures/Promises/Reactive •async/await ...

Concurrency with coroutines

suspend fun placeOrder(order: Order): Response =coroutineScope {

val account = async { accountService.loadAccount(order) }val margin = async { marginService.loadMargin(order) }validateOrder(order, account.await(), margin.await())

}

Fails?

Page 87: Server-side Kotlin with Coroutines · •async/await asyncfun loadMargin(account: Account): Task But how? •Callbacks •Futures/Promises/Reactive •async/await ...

Concurrency with coroutines

suspend fun placeOrder(order: Order): Response =coroutineScope {

val account = async { accountService.loadAccount(order) }val margin = async { marginService.loadMargin(order) }validateOrder(order, account.await(), margin.await())

}

Fails?Cancels

Page 88: Server-side Kotlin with Coroutines · •async/await asyncfun loadMargin(account: Account): Task But how? •Callbacks •Futures/Promises/Reactive •async/await ...

Concurrency with coroutines

suspend fun placeOrder(order: Order): Response =coroutineScope {

val account = async { accountService.loadAccount(order) }val margin = async { marginService.loadMargin(order) }validateOrder(order, account.await(), margin.await())

}

Fails?Cancels

Cancels

Page 89: Server-side Kotlin with Coroutines · •async/await asyncfun loadMargin(account: Account): Task But how? •Callbacks •Futures/Promises/Reactive •async/await ...

Concurrency with coroutines

suspend fun placeOrder(order: Order): Response =coroutineScope {

val account = async { accountService.loadAccount(order) }val margin = async { marginService.loadMargin(order) }validateOrder(order, account.await(), margin.await())

}

Waits for completion of all children

Page 90: Server-side Kotlin with Coroutines · •async/await asyncfun loadMargin(account: Account): Task But how? •Callbacks •Futures/Promises/Reactive •async/await ...

Enforcing structure

Page 91: Server-side Kotlin with Coroutines · •async/await asyncfun loadMargin(account: Account): Task But how? •Callbacks •Futures/Promises/Reactive •async/await ...

Without coroutine scope?

suspend fun placeOrder(order: Order): Response {val account = async { accountService.loadAccount(order) }val margin = async { marginService.loadMargin(order) }return validateOrder(order, account.await(), margin.await())

}

Page 92: Server-side Kotlin with Coroutines · •async/await asyncfun loadMargin(account: Account): Task But how? •Callbacks •Futures/Promises/Reactive •async/await ...

Without coroutine scope?

suspend fun placeOrder(order: Order): Response {val account = async { accountService.loadAccount(order) }val margin = async { marginService.loadMargin(order) }return validateOrder(order, account.await(), margin.await())

}

ERROR: Unresolved reference.

Page 93: Server-side Kotlin with Coroutines · •async/await asyncfun loadMargin(account: Account): Task But how? •Callbacks •Futures/Promises/Reactive •async/await ...

Extensions of CoroutineScope

fun <T> CoroutineScope.async(context: CoroutineContext = EmptyCoroutineContext,start: CoroutineStart = CoroutineStart.DEFAULT,block: suspend CoroutineScope.() -> T

): Deferred<T>

Page 94: Server-side Kotlin with Coroutines · •async/await asyncfun loadMargin(account: Account): Task But how? •Callbacks •Futures/Promises/Reactive •async/await ...

Convention

fun CoroutineScope.bg(params: Params) = launch { // …

}

Launches new coroutine

Page 95: Server-side Kotlin with Coroutines · •async/await asyncfun loadMargin(account: Account): Task But how? •Callbacks •Futures/Promises/Reactive •async/await ...

Types as documentation

fun foo(params: Params): Response

suspend fun foo(params: Params): Response

fun CoroutineScope.foo(params: Params): Response

Fast, local

Remote, or slow

Side effect - bg

Page 96: Server-side Kotlin with Coroutines · •async/await asyncfun loadMargin(account: Account): Task But how? •Callbacks •Futures/Promises/Reactive •async/await ...

Types are enforced

fun foo(params: Params): Response

suspend fun foo(params: Params): Response

fun CoroutineScope.foo(params: Params): Response

Not allowed

But must provide scope explicitly

Using coroutineScope { … }

Fast, local

Remote, or slow

Side effect - bg

Page 97: Server-side Kotlin with Coroutines · •async/await asyncfun loadMargin(account: Account): Task But how? •Callbacks •Futures/Promises/Reactive •async/await ...

Green threads / fibersAlternative way to async

Page 98: Server-side Kotlin with Coroutines · •async/await asyncfun loadMargin(account: Account): Task But how? •Callbacks •Futures/Promises/Reactive •async/await ...

Green threads / Fibers

ET 2

ET N

Executor Threads

ET 1

F 2

F M

Fibers

F 1

~ Coroutines Hidden from developer

Page 99: Server-side Kotlin with Coroutines · •async/await asyncfun loadMargin(account: Account): Task But how? •Callbacks •Futures/Promises/Reactive •async/await ...

Fibers promise

•Develop just like with threads• Everything is effectively suspendable

Page 100: Server-side Kotlin with Coroutines · •async/await asyncfun loadMargin(account: Account): Task But how? •Callbacks •Futures/Promises/Reactive •async/await ...

Marking with suspendpays off at scale

Page 101: Server-side Kotlin with Coroutines · •async/await asyncfun loadMargin(account: Account): Task But how? •Callbacks •Futures/Promises/Reactive •async/await ...

Thread switchingAnd how to avoid it

Page 102: Server-side Kotlin with Coroutines · •async/await asyncfun loadMargin(account: Account): Task But how? •Callbacks •Futures/Promises/Reactive •async/await ...

ET 2

ET N

Executor Threads

Clients

Threads

ET 1

Service 1 Threads

S1 1ST M1

Service 2 Threads

S1 1ST M2

Service 3 Threads

S1 1ST M3

Page 103: Server-side Kotlin with Coroutines · •async/await asyncfun loadMargin(account: Account): Task But how? •Callbacks •Futures/Promises/Reactive •async/await ...

ET 2

ET N

Executor Threads

Clients

Solution – shared thread pool

ET 1

Page 104: Server-side Kotlin with Coroutines · •async/await asyncfun loadMargin(account: Account): Task But how? •Callbacks •Futures/Promises/Reactive •async/await ...

ET 2

ET N

Executor Threads

Clients

Solution – shared thread pool

ET 1!

Page 105: Server-side Kotlin with Coroutines · •async/await asyncfun loadMargin(account: Account): Task But how? •Callbacks •Futures/Promises/Reactive •async/await ...

ET 2

ET N

Executor Threads

Clients

Solution – shared thread pool

ET 1! ET N+1

Page 106: Server-side Kotlin with Coroutines · •async/await asyncfun loadMargin(account: Account): Task But how? •Callbacks •Futures/Promises/Reactive •async/await ...

ET 2

ET N

Executor Threads

Clients

Solution – shared thread pool

ET 1! ET N+1

! ET N+2

Page 107: Server-side Kotlin with Coroutines · •async/await asyncfun loadMargin(account: Account): Task But how? •Callbacks •Futures/Promises/Reactive •async/await ...

ET 2

ET N

Executor Threads

Clients

Solution – shared thread pool

ET 1! ET N+1

!

ET M!

ET N+2

ET N+M

Page 108: Server-side Kotlin with Coroutines · •async/await asyncfun loadMargin(account: Account): Task But how? •Callbacks •Futures/Promises/Reactive •async/await ...

withContext for IO

suspend fun loadAccount(order: Order): Account = withContext(dispatcher) {

// some blocking code here....}

val dispatcher =Executors.newFixedThreadPool(M2).asCoroutineDispatcher()

Page 109: Server-side Kotlin with Coroutines · •async/await asyncfun loadMargin(account: Account): Task But how? •Callbacks •Futures/Promises/Reactive •async/await ...

withContext for Dispatсhers.IO

suspend fun loadAccount(order: Order): Account = withContext(Dispatchers.IO) {

// some blocking code here....}

No thread switch from Dispatchers.Default pool

Page 110: Server-side Kotlin with Coroutines · •async/await asyncfun loadMargin(account: Account): Task But how? •Callbacks •Futures/Promises/Reactive •async/await ...

ET 2

ET N

Executor Threads

Clients

Solution – shared thread pool

ET 1

Dispatchers.Default

Page 111: Server-side Kotlin with Coroutines · •async/await asyncfun loadMargin(account: Account): Task But how? •Callbacks •Futures/Promises/Reactive •async/await ...

ET 2

ET N

Executor Threads

Clients

Solution – shared thread pool

ET 1! ET N+1

!

ET M!

ET N+2

ET N+M

Dispatchers.DefaultDispatchers.IO

Page 112: Server-side Kotlin with Coroutines · •async/await asyncfun loadMargin(account: Account): Task But how? •Callbacks •Futures/Promises/Reactive •async/await ...

Coroutines and data streams

Page 113: Server-side Kotlin with Coroutines · •async/await asyncfun loadMargin(account: Account): Task But how? •Callbacks •Futures/Promises/Reactive •async/await ...

Returning many responses

suspend fun foo(params: Params): Response One response

suspend fun foo(params: Params): List<Response> Many responses

suspend fun foo(params: Params): ????<Response> Many responses async?

Page 114: Server-side Kotlin with Coroutines · •async/await asyncfun loadMargin(account: Account): Task But how? •Callbacks •Futures/Promises/Reactive •async/await ...

Channel

receive()send()

Page 115: Server-side Kotlin with Coroutines · •async/await asyncfun loadMargin(account: Account): Task But how? •Callbacks •Futures/Promises/Reactive •async/await ...

Producer Builder

fun CoroutineScope.foo(): ReceiveChannel<Int> = produce {for (i in 1..10) {

send(i)delay(100)

}}

Channel type

Can be async

Page 116: Server-side Kotlin with Coroutines · •async/await asyncfun loadMargin(account: Account): Task But how? •Callbacks •Futures/Promises/Reactive •async/await ...

Consumer

fun CoroutineScope.foo(): ReceiveChannel<Int> = produce {for (i in 1..10) {

send(i)delay(100)

}}

fun main() = runBlocking<Unit> {for (x in foo()) {

println(x)}

}

Page 117: Server-side Kotlin with Coroutines · •async/await asyncfun loadMargin(account: Account): Task But how? •Callbacks •Futures/Promises/Reactive •async/await ...

Where’s the catch?

fun CoroutineScope.foo(): ReceiveChannel<Int> = produce {for (i in 1..10) {

send(i)delay(100)

}}

fun main() = runBlocking<Unit> {for (x in foo()) {

println(x)}

}

Page 118: Server-side Kotlin with Coroutines · •async/await asyncfun loadMargin(account: Account): Task But how? •Callbacks •Futures/Promises/Reactive •async/await ...

Where’s the catch?

fun CoroutineScope.foo(): ReceiveChannel<Int> = produce {for (i in 1..10) {

send(i)delay(100)

}}

fun main() = runBlocking<Unit> {for (x in foo()) {

println(x)}

}

Creates coroutine

Page 119: Server-side Kotlin with Coroutines · •async/await asyncfun loadMargin(account: Account): Task But how? •Callbacks •Futures/Promises/Reactive •async/await ...

Try this!

fun CoroutineScope.foo(): ReceiveChannel<Int> = produce {for (i in 1..10) {

send(i)delay(100)

}}

fun main() = runBlocking<Unit> {foo()

}

Waits for completion of children

!

Page 120: Server-side Kotlin with Coroutines · •async/await asyncfun loadMargin(account: Account): Task But how? •Callbacks •Futures/Promises/Reactive •async/await ...

Kotlin FlowsDisclaimer: available in preview only, not stable yet

Page 121: Server-side Kotlin with Coroutines · •async/await asyncfun loadMargin(account: Account): Task But how? •Callbacks •Futures/Promises/Reactive •async/await ...

Flow example

fun bar(): Flow<Int> = flow {for (i in 1..10) {

emit(i)delay(100)

}}

~ Asynchronous sequence

Page 122: Server-side Kotlin with Coroutines · •async/await asyncfun loadMargin(account: Account): Task But how? •Callbacks •Futures/Promises/Reactive •async/await ...

Flow example

fun bar(): Flow<Int> = flow {for (i in 1..10) {

emit(i)delay(100)

}}

fun main() = runBlocking<Unit> {bar().collect { x ->

println(x)}

}

Page 123: Server-side Kotlin with Coroutines · •async/await asyncfun loadMargin(account: Account): Task But how? •Callbacks •Futures/Promises/Reactive •async/await ...

Try this!

fun bar(): Flow<Int> = flow {for (i in 1..10) {

emit(i)delay(100)

}}

fun main() = runBlocking<Unit> {bar()

}

Flow is cold: describes the data, does not run it until collected

!

Page 124: Server-side Kotlin with Coroutines · •async/await asyncfun loadMargin(account: Account): Task But how? •Callbacks •Futures/Promises/Reactive •async/await ...

Flow example

fun bar(): Flow<Int> = flow {for (i in 1..10) {

emit(i)delay(100)

}}

fun main() = runBlocking<Unit> {bar()

.map { it * it }

.toList()} Write regular code!

Similar to collections / sequences

Page 125: Server-side Kotlin with Coroutines · •async/await asyncfun loadMargin(account: Account): Task But how? •Callbacks •Futures/Promises/Reactive •async/await ...

Thank you

Want to learn more?Questions?

elizarov @Roman Elizarov

relizarov

Page 126: Server-side Kotlin with Coroutines · •async/await asyncfun loadMargin(account: Account): Task But how? •Callbacks •Futures/Promises/Reactive •async/await ...