Robuste Coroutine-Architekturen entwerfen
Kombinieren Sie supervisorScope, Wiederholungslogik und Handler für nebenläufige Abläufe auf Produktionsniveau.
Robuste Coroutine-Architekturen entwerfen ist eine kostenlose Kotlin Academy-Lektion auf CoddyKit. Dies ist Lektion 4 von 4. Du kannst die komplette Lektion unten kostenlos lesen – dann übst du sie direkt im Browser mit einem integrierten Code-Editor und einem KI-Tutor rund um die Uhr. Sie ist Teil des Kotlin Academy-Lernpfads, und dein Fortschritt wird über Web und CoddyKit-App synchronisiert. Der Kotlin Academy-Kurs umfasst insgesamt 4 Lektionen.
Was macht Coroutines resilient?
Resiliente Coroutine-Architekturen behandeln Fehler kontrolliert: Sie isolieren Fehler, wiederholen vorübergehende Fehler, brechen veraltete Arbeit ab und geben Ressourcen deterministisch frei.
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") }Muster für einen App-Level-Scope
Erstellen Sie einen einzigen CoroutineScope auf App-Ebene mit SupervisorJob + handler. Injizieren Sie ihn in Services, damit alle denselben Lebenszyklus verwenden.
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()
}Wiederholungsversuche mit exponentiellem Backoff
Verpacken Sie Netzwerkaufrufe in eine Wiederholungsschleife mit exponentiellem Backoff, um vorübergehende Fehler kontrolliert zu behandeln.
import kotlinx.coroutines.*
suspend fun <T> retryWithBackoff(
times: Int = 3,
initialDelay: Long = 100,
block: suspend () -> T
): T {
var delay = initialDelay
repeat(times - 1) { attempt ->
try { return block() }
catch (e: Exception) {
if (e is CancellationException) throw e
println("Attempt ${attempt+1} failed, retrying in ${delay}ms")
delay(delay)
delay *= 2
}
}
return block()
}
fun main() = runBlocking {
var n = 0
val result = retryWithBackoff {
if (n++ < 2) throw RuntimeException("transient")
"success"
}
println(result)
}Circuit-Breaker-Muster
Ein Circuit Breaker beendet die Aufrufe eines fehlerhaften Services nach N Fehlern und aktiviert sie nach einer Abkühlphase wieder – dadurch werden Kaskadenfehler verhindert.
import kotlinx.coroutines.*
class CircuitBreaker(val maxFailures: Int, val cooldownMs: Long) {
private var failures = 0
private var openUntil = 0L
suspend fun <T> call(block: suspend () -> T): T {
if (System.currentTimeMillis() < openUntil) throw RuntimeException("Circuit open")
return try {
val result = block()
failures = 0
result
} catch (e: Exception) {
if (e is CancellationException) throw e
if (++failures >= maxFailures) openUntil = System.currentTimeMillis() + cooldownMs
throw e
}
}
}Jeden externen Aufruf mit einem Timeout versehen
Verpacken Sie externe I/O immer mit withTimeout oder withTimeoutOrNull. Lassen Sie niemals zu, dass eine hängende Verbindung eine Coroutine unbegrenzt blockiert.
import kotlinx.coroutines.*
suspend fun fetchWithTimeout(url: String): String? = withTimeoutOrNull(3000) {
// ktor: client.get(url).body()
delay(100) // simulate
"response from $url"
}
fun main() = runBlocking {
val result = fetchWithTimeout("https://api.example.com")
println(result ?: "Timed out")
}Strukturierter Scope pro Feature
Erstellen Sie pro Feature oder Bildschirm einen separaten CoroutineScope mit einem eigenen SupervisorJob. Brechen Sie ihn ab, wenn das Feature zerstört wird.
import kotlinx.coroutines.*
class FeatureController {
private val scope = CoroutineScope(SupervisorJob() + Dispatchers.Main)
fun start() {
scope.launch { /* load data */ }
scope.launch { /* subscribe to updates */ }
}
fun destroy() = scope.cancel() // cancels all feature coroutines
}Ressourcensicherheit mit use()
Verwenden Sie use { } für AutoCloseable-Ressourcen. Kombinieren Sie dies mit der Coroutine-Abbruchbehandlung: Ressourcen werden auch dann geschlossen, wenn die Coroutine abgebrochen wird.
import kotlinx.coroutines.*
class Connection : AutoCloseable {
override fun close() = println("Connection closed")
suspend fun fetch(): String { delay(100); return "data" }
}
fun main() = runBlocking {
val job = launch {
Connection().use { conn ->
println(conn.fetch())
} // close() called even on cancellation
}
delay(50)
job.cancelAndJoin()
}Kontrolliertes Herunterfahren
Implementieren Sie ein kontrolliertes Herunterfahren: Nehmen Sie keine neue Arbeit mehr an, warten Sie, bis laufende Coroutines abgeschlossen sind, und brechen Sie anschließend den Scope ab.
import kotlinx.coroutines.*
class WorkQueue {
private val scope = CoroutineScope(SupervisorJob())
private val jobs = mutableListOf<Job>()
fun submit(block: suspend () -> Unit) {
jobs += scope.launch { block() }
}
suspend fun shutdown() {
jobs.forEach { it.join() } // wait for all
scope.cancel() // then cancel scope
}
}
fun main() = runBlocking {
val q = WorkQueue()
repeat(3) { i -> q.submit { delay(50); println("Task $i done") } }
q.shutdown()
println("Queue shut down cleanly")
}Beobachtbarkeit: CoroutineName
Versehen Sie Coroutines zur Fehlersuche mit CoroutineName. Namen erscheinen in Stacktraces und können in Exception-Handlern für eine strukturierte Protokollierung verwendet werden.
import kotlinx.coroutines.*
fun main() = runBlocking {
val handler = CoroutineExceptionHandler { ctx, e ->
println("[${ctx[CoroutineName]?.name}] Failed: ${e.message}")
}
CoroutineScope(SupervisorJob() + handler).apply {
launch(CoroutineName("UserLoader")) { throw RuntimeException("DB error") }
launch(CoroutineName("Analytics")) { delay(100); println("Analytics ok") }
delay(200); cancel()
}
}GlobalScope vermeiden
Verwenden Sie GlobalScope niemals in der Produktion. Dadurch entstehen Coroutines ohne übergeordnete Coroutine, ohne Lebenszyklusverwaltung und ohne strukturierte Abbruchbehandlung. Verwenden Sie stattdessen Scopes mit passendem Lebenszyklus.
import kotlinx.coroutines.*
// BAD — GlobalScope leaks coroutines:
// GlobalScope.launch { delay(Long.MAX_VALUE) }
// GOOD — scoped, cancellable:
val scope = CoroutineScope(SupervisorJob() + Dispatchers.Default)
scope.launch { delay(100); println("Scoped") }
fun main() = runBlocking { delay(200); scope.cancel() }Resilienz testen
Verwenden Sie runTest mit TestCoroutineScheduler, um Fehler, Timeouts und Wiederholungen in Unit-Tests ohne echte Verzögerungen zu simulieren.
import kotlinx.coroutines.*
import kotlinx.coroutines.test.*
fun testRetry() = runTest {
var attempts = 0
val result = retryWithBackoff(3, 100) {
if (attempts++ < 2) throw RuntimeException("fail")
"ok"
}
println(result) // "ok"
}
// In test, virtual time advances instantly through delaysKurze Überprüfung
Welche Kombination bildet die Grundlage für einen resilienten, langlebigen Coroutine-Scope?
Zusammenfassung
Resiliente Architekturen kombinieren SupervisorJob zur Isolierung, retryWithBackoff für vorübergehende Fehler, withTimeout für festgefahrene I/O, finally/NonCancellable zur Bereinigung und CoroutineExceptionHandler für die Beobachtbarkeit.
Häufig gestellte Fragen
Ist die Lektion „Robuste Coroutine-Architekturen entwerfen“ kostenlos?
Ja — der vollständige Text von „Robuste Coroutine-Architekturen entwerfen“ ist hier im Web kostenlos zu lesen. Um sie interaktiv zu üben (integrierter Code-Editor und 24/7 KI-Tutor) und den Rest des Kotlin Academy-Kurses freizuschalten, upgrade auf CoddyKit PRO. Der Kotlin Academy-Kurs umfasst insgesamt 4 Lektionen.
Was lerne ich in „Robuste Coroutine-Architekturen entwerfen“?
Kombinieren Sie supervisorScope, Wiederholungslogik und Handler für nebenläufige Abläufe auf Produktionsniveau. Du übst Kotlin Academy mit praktischem Code, den du direkt im Browser ausführst, und ein 24/7 KI-Tutor beantwortet deine Fragen während du die Lektion bearbeitest.
Brauche ich Erfahrung, um Kotlin Academy zu starten?
Keine Vorkenntnisse erforderlich. Kotlin Academy auf CoddyKit ist für Anfänger bis fortgeschrittene Lernende strukturiert, sodass du hier starten oder von Anfang an beginnen und in deinem eigenen Tempo voranschreiten kannst. Dies ist Lektion 4 von 4.
Wie lange dauert die Lektion „Robuste Coroutine-Architekturen entwerfen“?
Die meisten CoddyKit-Lektionen dauern etwa 5–10 Minuten. Jede ist kompakt und interaktiv, sodass du stetig Fortschritte machst und genau dort weitermachst, wo du aufgehört hast – im Web und in der App.
Kann ich in dieser Kotlin Academy-Lektion Code schreiben und ausführen?
Ja. Jede Kotlin Academy-Lektion enthält einen integrierten Code-Editor, sodass du echten Code direkt in deinem Browser schreibst und ausführst und sofort KI-Feedback erhältst — ohne lokale Einrichtung erforderlich.
Alle Lektionen in diesem Kurs
- SupervisorJob vs. Job: Fehlerisolierung
- CoroutineExceptionHandler: globaler Handler für unbehandelte Exceptions
- Exception-Weitergabe bei async/await
- Robuste Coroutine-Architekturen entwerfen