Coming from Raw Coroutines¶
If you're using coroutineScope { async { } } for parallel execution, this guide shows how KAP simplifies your code while keeping all the structured concurrency guarantees you rely on.
KAP is built ON coroutines¶
KAP doesn't replace kotlinx.coroutines — it uses it internally. Async { } creates a coroutineScope. .with uses async. All structured concurrency rules still apply:
- Parent cancels → all children cancel
- One child fails → siblings cancel (unless
.settled()) CancellationExceptionis never caughtCoroutineContextpropagates to all branches
Simple parallel: async/await → kap + .with¶
6 lines → 4 lines. No shuttle variables. Swap two .with lines? Compile error.
Phased execution: nested coroutineScope → .then¶
// Where does phase 1 end? Read every line to find out.
val result = coroutineScope {
val dA = async { fetchA() }
val dB = async { fetchB() }
val a = dA.await()
val b = dB.await()
val validated = validate(a, b) // invisible barrier
val dC = async { fetchC() }
val dD = async { fetchD() }
Result(a, b, validated, dC.await(), dD.await())
}
Bounded concurrency: Semaphore → traverse(concurrency)¶
Timeout with fallback: withTimeoutOrNull → .timeout¶
Parallel fallback: sequential → timeoutRace¶
Error recovery: try/catch → .recover¶
Retry: manual loop → Schedule¶
var result: String? = null
var lastException: Exception? = null
repeat(3) { attempt ->
try {
result = fetchUser()
return@repeat
} catch (e: Exception) {
if (e is CancellationException) throw e
lastException = e
delay(100L * (attempt + 1)) // linear backoff, hardcoded
}
}
result ?: throw lastException!!
Resource cleanup: try/finally → bracket¶
Partial failure: supervisorScope → .settled()¶
Cheat sheet¶
| Raw Coroutines | KAP |
|---|---|
coroutineScope { async { } } |
Async { kap(::T).with { } } |
async { }.await() |
.with { } |
| suspend call between phases | .then { } |
nested coroutineScope |
.andThen { ctx -> } |
Semaphore + async |
traverse(concurrency) |
withTimeoutOrNull |
.timeout(d) { default } |
try/catch |
.recover { } |
try/finally |
bracket(acquire, use, release) |
supervisorScope |
.settled() |
select { } |
race() / raceN() |
| manual retry loop | retry(Schedule) |