0Pricing
Kotlin Academy · Pelajaran

Merancang Arsitektur Coroutine yang Tangguh

Gabungkan supervisorScope, logika percobaan ulang, dan handler untuk konkurensi siap produksi.

Merancang Arsitektur Coroutine yang Tangguh adalah pelajaran Kotlin Academy gratis di CoddyKit. Ini adalah pelajaran 4 dari 4. Kamu bisa membaca pelajaran lengkapnya di bawah secara gratis — lalu praktikkan langsung di browser dengan editor kode bawaan dan tutor AI 24/7. Ini adalah bagian dari jalur belajar Kotlin Academy, dan progresmu tersinkronisasi di web dan aplikasi CoddyKit. Kursus Kotlin Academy mencakup 4 pelajaran total.

Apa yang Membuat Korutin Tangguh?

Arsitektur korutin yang tangguh menangani kegagalan dengan baik: mengisolasi kegagalan, mencoba ulang kesalahan sementara, membatalkan pekerjaan yang sudah usang, dan membersihkan sumber daya secara deterministik.

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") }

Pola Cakupan Tingkat Aplikasi

Buat satu CoroutineScope tingkat aplikasi dengan SupervisorJob + handler. Masukkan cakupan tersebut ke layanan agar semuanya berbagi siklus hidup yang sama.

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()
}

Percobaan Ulang dengan Penundaan Eksponensial

Bungkus panggilan jaringan dalam perulangan percobaan ulang dengan penundaan eksponensial untuk menangani kegagalan sementara dengan baik.

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)
}

Pola Pemutus Sirkuit

Pemutus sirkuit berhenti memanggil layanan yang gagal setelah N kegagalan dan membukanya kembali setelah masa pendinginan—sehingga mencegah kegagalan berantai.

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
        }
    }
}

Batas Waktu untuk Setiap Panggilan Eksternal

Selalu bungkus I/O eksternal dengan withTimeout atau withTimeoutOrNull. Jangan pernah membiarkan koneksi yang macet memblokir korutin tanpa batas.

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")
}

Cakupan Terstruktur per Fitur

Buat CoroutineScope terpisah untuk setiap fitur atau layar, dengan SupervisorJob miliknya sendiri. Batalkan cakupan tersebut saat fitur dihancurkan.

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
}

Keamanan Sumber Daya dengan Blok Penggunaan

Gunakan use { } untuk sumber daya AutoCloseable. Gabungkan dengan pembatalan korutin: sumber daya tetap ditutup meskipun korutin dibatalkan.

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()
}

Penghentian yang Lancar

Terapkan penghentian yang lancar: berhenti menerima pekerjaan baru, tunggu korutin yang sedang berjalan hingga selesai, lalu batalkan cakupannya.

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")
}

Observabilitas: CoroutineName

Beri label pada korutin dengan CoroutineName untuk proses debug. Nama tersebut muncul dalam pelacakan tumpukan dan dapat digunakan dalam penangan pengecualian untuk pencatatan log terstruktur.

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()
    }
}

Hindari GlobalScope

Jangan pernah menggunakan GlobalScope dalam produksi. Cakupan tersebut membuat korutin tanpa induk, tanpa pengelolaan siklus hidup, dan tanpa pembatalan terstruktur. Sebagai gantinya, gunakan alternatif yang memiliki cakupan.

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() }

Menguji Ketangguhan

Gunakan runTest dengan TestCoroutineScheduler untuk menyimulasikan kegagalan, batas waktu, dan percobaan ulang dalam pengujian unit tanpa penundaan nyata.

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 delays

Pemeriksaan Singkat

Kombinasi apa yang menjadi dasar cakupan korutin berumur panjang yang tangguh?

Ringkasan

Arsitektur yang tangguh menggabungkan SupervisorJob untuk isolasi, retryWithBackoff untuk kesalahan sementara, withTimeout untuk I/O yang macet, blok akhir/NonCancellable untuk pembersihan, dan CoroutineExceptionHandler untuk observabilitas.

Pertanyaan yang Sering Diajukan

Apakah pelajaran “Merancang Arsitektur Coroutine yang Tangguh” gratis?

Ya — teks lengkap “Merancang Arsitektur Coroutine yang Tangguh” gratis dibaca di sini di web. Untuk praktiknya secara interaktif (editor kode bawaan dan tutor AI 24/7) dan buka sisa kursus Kotlin Academy, upgrade ke CoddyKit PRO. Kursus Kotlin Academy mencakup 4 pelajaran total.

Apa yang akan aku pelajari di “Merancang Arsitektur Coroutine yang Tangguh”?

Gabungkan supervisorScope, logika percobaan ulang, dan handler untuk konkurensi siap produksi. Kamu berlatih Kotlin Academy dengan kode praktik yang langsung kamu jalankan di browser, dan tutor AI 24/7 menjawab pertanyaanmu saat kamu mengerjakan pelajaran ini.

Apakah aku perlu pengalaman untuk memulai Kotlin Academy?

Tidak diperlukan pengalaman sebelumnya. Kotlin Academy di CoddyKit dirancang untuk pemula hingga pelajar tingkat lanjut, jadi kamu bisa memulai di sini atau dari awal dan belajar sesuai kecepatan kamu sendiri. Ini adalah pelajaran 4 dari 4.

Berapa lama pelajaran “Merancang Arsitektur Coroutine yang Tangguh” memakan waktu?

Sebagian besar pelajaran CoddyKit memakan waktu sekitar 5–10 menit. Setiap pelajaran ringkas dan interaktif, jadi kamu membuat kemajuan stabil dan melanjutkan dari tempat kamu tinggalkan di web dan aplikasi.

Bisakah aku menulis dan menjalankan kode dalam pelajaran Kotlin Academy ini?

Ya. Setiap pelajaran Kotlin Academy menyertakan editor kode bawaan, jadi kamu menulis dan menjalankan kode nyata langsung di browser dan mendapatkan umpan balik AI instan — tidak diperlukan penyiapan lokal.

Semua pelajaran dalam kursus ini

  1. SupervisorJob vs Job: Isolasi Kegagalan
  2. CoroutineExceptionHandler: Penangan Global yang Tidak Tertangkap
  3. Propagasi Exception async/await
  4. Merancang Arsitektur Coroutine yang Tangguh
← Kembali ke Kotlin Academy