Hero image

Handling multiple requests with async coroutine builder in Kotlin

Feb 03, 2024
Kotlin

In this previous article, we introduced the launch coroutine builder to start a coroutine that doesn’t have a result. When your task has a result that you want to use you can use the async coroutine builder.

async is useful in scenarios where you make multiple API requests that can be run concurrently and combined once all have finished - this is a common scenario in microservice architectured backends for example. By performing the operations concurrently we can return the combined response sooner as we are not wasting time waiting for the first operation to finish before moving on to the next.

Async Coroutine Syntax

The basic syntax of the async coroutine builder is similar to launch, i.e. pass a block of code to execute. async returns an instance of Deferred<T> which represents the deferred result of the coroutine, similar to a Promise in Javascript. Deferred<T> has a method called await that will wait for the coroutine to complete and return the result.

val deferredResult = async {
    fetchData()
}

// you can perform other tasks while waiting for the coroutine to complete

val result = deferredResult.await()

Real World Example

In the example below we start two async requests to get the user’s bank balance and transactions. These two requests are independent so they can run concurrently, we do however want to wait for both requests to be completed before printing the results. You can imagine this sort of code in an API that gathers and summarises a user’s finances, the requests must have been completed to send the response to the client.

suspend fun fetchBalance(): BigDecimal {
    delay(500)
    return "1200.00".toBigDecimal()
}

suspend fun fetchTransactions(): List<BigDecimal> {
    delay(1000)
    return listOf(
        "50.00".toBigDecimal(),
        "75.00".toBigDecimal()
    )
}

fun main() = runBlocking {
    val balanceDeferred = async { fetchBalance() }
    val transactionsDeferred = async { fetchTransactions() }

    val balance = balanceDeferred.await()
    val transactions = transactionsDeferred.await()

    println("Balance: $balance")
    println("Total Spending: ${transactions.sumOf { it }}")
}

The output is printed:

println("Balance: 100.00")
println("Total Spending: 125.00")