Designing Resilient Coroutine Architectures
Combine supervisorScope, retry logic, and handlers for production-grade concurrency.
What Makes Coroutines Resilient?
Resilient coroutine architectures handle failures gracefully: they isolate failures, retry transient errors, cancel stale work, and clean up resources deterministically.
import kotlinx.coroutines.*
// Resilience pillars:
// 1. Failure isolation (SupervisorJob)
// 2. Retry with backoff (retry operator / loop)
// 3. Timeout guards (withTimeout)
// 4. Clean teardown (finally + NonCancellable)
// 5. Observability (CoroutineExceptionHandler)
fun main() = runBlocking { println("Design for failure from the start") }App-Level Scope Pattern
Create a single app-level CoroutineScope with SupervisorJob + handler. Inject it into services so they all share the same lifecycle.
import kotlinx.coroutines.*
object AppCoroutineScope {
private val handler = CoroutineExceptionHandler { _, e ->
println("[AppScope] Uncaught: ${e.message}")
}
val scope = CoroutineScope(SupervisorJob() + Dispatchers.Default + handler)
fun cancel() = scope.cancel()
}All lessons in this course
- SupervisorJob vs Job: Failure Isolation
- CoroutineExceptionHandler: Global Uncaught Handler
- async/await Exception Propagation
- Designing Resilient Coroutine Architectures