Combine two independent asynchronous results
Implement a summary loader with injectable suspending functions. Keep the work inside the caller's structured lifetime and cancel sibling work when an all-or-nothing result becomes impossible.
import kotlinx.coroutines.*
data class Summary(val lessons: Int, val minutes: Int)
suspend fun summary(
lessonCount: suspend () -> Int,
studyMinutes: suspend () -> Int
): Summary = coroutineScope {
val lessons = async { lessonCount() }
val minutes = async { studyMinutes() }
Summary(lessons.await(), minutes.await())
}
Starting both children before awaiting allows overlap when their operations suspend. Writing async { ... }.await() twice sequentially would wait for the first before starting the second.
Acceptance checks
Use fake loaders returning 4 and 75, verify the combined result, make one loader fail, and cancel the caller while both wait. Confirm no child continues after the scope has finished. Use coroutine test utilities rather than assertions based on wall-clock sleeps.
Extension: design a partial-success version with explicit result types and supervision. Explain why swallowing every failure into zero would produce a misleading summary.