Real World Example

Paytm-style Dashboard Widgets

A wallet dashboard shows balance, recent transactions and offers. If the offers service is down, the user must still see the balance. Each widget loads in a supervisorScope and converts its failure into an error state.

supervisorScope
 ├─ async balance       ✓  Rs 2,500
 ├─ async transactions  ✓  3 items
 └─ async offers        ✗  "Offers unavailable" card

Code

Example

import kotlinx.coroutines.*
import java.io.IOException

sealed interface Widget {
    data class Ready(val title: String, val body: String) : Widget
    data class Failed(val title: String, val reason: String) : Widget
}

suspend fun fetchBalance(): String { delay(100); return "Rs 2,500" }
suspend fun fetchTransactions(): String { delay(150); return "3 transactions today" }
suspend fun fetchOffers(): String { delay(50); throw IOException("offers-service 503") }

suspend fun loadWidget(title: String, load: suspend () -> String): Widget = try {
    Widget.Ready(title, load())
} catch (e: CancellationException) {
    throw e
} catch (e: Exception) {
    Widget.Failed(title, e.message ?: "unknown")
}

suspend fun loadDashboard(): List<Widget> = supervisorScope {
    listOf(
        async { loadWidget("Balance", ::fetchBalance) },
        async { loadWidget("Transactions", ::fetchTransactions) },
        async { loadWidget("Offers", ::fetchOffers) },
    ).awaitAll()
}

fun main() = runBlocking {
    loadDashboard().forEach { w ->
        when (w) {
            is Widget.Ready -> println("[OK]    ${w.title}: ${w.body}")
            is Widget.Failed -> println("[ERROR] ${w.title}: ${w.reason}")
        }
    }
}

Output

[OK]    Balance: Rs 2,500
[OK]    Transactions: 3 transactions today
[ERROR] Offers: offers-service 503