Kotlin Academy · Oppitunti

SupervisorJob vs Job: virheiden eristäminen

Käyttäkää SupervisorJobia estämään yhden lapsen virheen aiheuttama sisarusten peruutus.

Oppitunti 1/413 vaihetta

SupervisorJob vs Job: virheiden eristäminen on ilmainen Kotlin Academy-oppitunti CoddyKitissä. Tämä on oppitunti 1/4. Voit lukea tästä oppimispolusta kokonaan mitkä tahansa 3 oppituntia ilmaiseksi — sen jälkeen CoddyKit PRO avaa kaikki oppitunnit sekä käytännön harjoittelun sisäänrakennetulla koodieditorilla ja ympäri vuorokauden toimivalla tekoälytuutorilla. Oppitunti kuuluu Kotlin Academy-oppimispolkuun, ja edistymisesi synkronoituu verkon ja CoddyKit-sovelluksen välillä. Kotlin Academy-kurssilla on yhteensä 4 oppituntia.

Jobin oletusarvoinen virheiden välitys

Tavallisen Job-työn kanssa lapsen epäonnistuminen peruuttaa vanhemman, joka puolestaan peruuttaa kaikki sisarukset. Yksi virhe kaataa koko hierarkian.

import kotlinx.coroutines.*
fun main() = runBlocking {
    try {
        coroutineScope {
            launch { delay(50); throw RuntimeException("child 1 failed") }
            launch { delay(1000); println("child 2 — never prints") }
        }
    } catch (e: RuntimeException) {
        println("Caught: ${e.message}")
    }
}

SupervisorJobin yleiskatsaus

SupervisorJob muuttaa sääntöä: lapsen epäonnistuminen EI peruuta sisaruksia tai vanhempaa. Jokainen lapsi epäonnistuu itsenäisesti.

import kotlinx.coroutines.*
fun main() = runBlocking {
    val supervisor = SupervisorJob()
    val scope = CoroutineScope(coroutineContext + supervisor)
    scope.launch { throw RuntimeException("child 1 failed") }
    scope.launch { delay(100); println("child 2 still runs") }
    delay(200)
    supervisor.cancel()
}

supervisorScope-rakentaja

supervisorScope { } luo scopet, jonka vanhempana on SupervisorJob. Se on suositusten mukainen tapa suorittaa toisistaan riippumattomia lapsia.

import kotlinx.coroutines.*
fun main() = runBlocking {
    supervisorScope {
        val job1 = launch {
            throw RuntimeException("job1 failed")
        }
        val job2 = launch {
            delay(100)
            println("job2 succeeded")
        }
        job1.join()  // wait for job1 (it failed)
        job2.join()  // job2 is unaffected
    }
}

Lapsien virheiden käsittely

supervisorScope-scopessa jokainen lapsi käsittelee oman poikkeuksensa. Lapsien käsittelemättömät poikkeukset on otettava kiinni kunkin lapsen kohdalla erikseen.

import kotlinx.coroutines.*
fun main() = runBlocking {
    supervisorScope {
        val result = async {
            delay(50)
            throw RuntimeException("async failed")
        }
        try {
            result.await()
        } catch (e: RuntimeException) {
            println("Caught from async: ${e.message}")
        }
        println("Scope continues")
    }
}

Job ja SupervisorJob scopen luonnin yhteydessä

Välitä SupervisorJob(), kun luot CoroutineScopen palvelulle tai ViewModellille, jonka pitäisi selviytyä yksittäisten lapsien epäonnistumisista.

import kotlinx.coroutines.*
class MyService {
    private val scope = CoroutineScope(Dispatchers.Default + SupervisorJob())
    fun startTask(name: String) {
        scope.launch {
            if (name == "fail") throw RuntimeException("$name failed")
            println("$name done")
        }
    }
    fun stop() = scope.cancel()
}
fun main() = runBlocking {
    val svc = MyService()
    svc.startTask("fail")
    svc.startTask("ok")
    delay(100)
    svc.stop()
}

viewModelScope käyttää SupervisorJobia

Androidin viewModelScope perustuu SupervisorJob-työhön. Yhden launch-kutsun epäonnistuminen ei peruuta ViewModelin muita korutiineja.

import kotlinx.coroutines.*
// Android ViewModel internals:
// val viewModelScope = CoroutineScope(SupervisorJob() + Dispatchers.Main.immediate)
// Each launch is independent — one failure doesn't crash the ViewModel
fun main() = runBlocking {
    println("viewModelScope = SupervisorJob + Main")
}

Rinnakkainen hajauttaminen supervisorScopen avulla

Käyttäkää supervisorScope + async -rakennetta rinnakkaisiin tehtäviin, joissa jotkin tehtävät voivat epäonnistua vaikuttamatta muihin.

import kotlinx.coroutines.*
fun main() = runBlocking {
    val results = supervisorScope {
        val a = async { delay(50); "result-A" }
        val b = async { throw RuntimeException("B failed") }
        val c = async { delay(30); "result-C" }
        listOf(
            runCatching { a.await() },
            runCatching { b.await() },
            runCatching { c.await() }
        )
    }
    results.forEach { println(it) }
}

Milloin tavallista Jobia käytetään

Käyttäkää tavallista Job-rakennetta (coroutineScope), kun kaikkien lasten on onnistuttava yhdessä — yhden epäonnistumisen tulee keskeyttää koko ryhmä. Se toimii kuin transaktio: kaikki tai ei mitään.

import kotlinx.coroutines.*
fun main() = runBlocking {
    try {
        coroutineScope {  // regular Job
            val a = async { delay(50); "A" }
            val b = async { throw RuntimeException("B failed") }
            println(a.await())
            println(b.await())  // throws — cancels a too
        }
    } catch (e: RuntimeException) {
        println("Transaction failed: ${e.message}")
    }
}

Poikkeusten välittyminen supervisorScopessa

supervisorScope-rakenteessa poikkeus välittyy scopeen vain, jos se karkaa lapsen ylimmältä tasolta — eli lapsessa ei ole try-catch-käsittelyä. Vanhempi ei näe sitä.

import kotlinx.coroutines.*
fun main() = runBlocking {
    supervisorScope {
        // Exception caught inside child — scope unaffected
        launch {
            try { throw RuntimeException("handled") }
            catch (e: Exception) { println("Child caught: ${e.message}") }
        }
        delay(100)
        println("Scope survived")
    }
}

CoroutineExceptionHandler ja SupervisorJob

Asentakaa CoroutineExceptionHandler supervisor-scopeen, jotta voitte kirjata käsittelemättömät lapsen epäonnistumiset lokiin tai reagoida niihin ilman, että scope kaatuu.

import kotlinx.coroutines.*
fun main() = runBlocking {
    val handler = CoroutineExceptionHandler { _, e ->
        println("Uncaught: ${e.message}")
    }
    val scope = CoroutineScope(SupervisorJob() + handler)
    scope.launch { throw RuntimeException("unhandled failure") }
    scope.launch { delay(100); println("still running") }
    delay(200)
    scope.cancel()
}

Eristettyjen epäonnistumisten yhteenveto

Job: yksi lapsi epäonnistuu → kaikki epäonnistuvat. SupervisorJob: lapset epäonnistuvat toisistaan riippumatta. Käyttäkää supervisoria palveluihin ja ViewModeleihin sekä tavallista Jobia transaktionaalisiin ryhmiin.

import kotlinx.coroutines.*
// Decision table:
// coroutineScope { }   -> Job: all-or-nothing
// supervisorScope { }  -> SupervisorJob: independent failures
// CoroutineScope(SupervisorJob()) -> long-lived service
fun main() = runBlocking { println("Pick the right job for the right scope") }

Pikatarkistus

Mikä scope estää lapsen epäonnistumista peruuttamasta sisaruksiaan?

Kertaus

Job: epäonnistuminen leviää sisaruksiin. SupervisorJob/supervisorScope: epäonnistumiset eristetään lapsikohtaisesti. Käyttäkää supervisorScopea rinnakkaisiin, toisistaan riippumattomiin tehtäviin ja tavallista coroutineScopea transaktionaalisiin ryhmiin.

Aloita maksutta

Opi Kotlin tekoälytuutorin avulla — ilmaiseksi

Kirjoita ja suorita oikeaa koodia selaimessa, saa välitöntä apua tekoälytuutorilta ympäri vuorokauden ja jatka siitä, mihin jäit, verkossa tai sovelluksessa.

Kurssit
51
Oppitunnit
203

Usein kysytyt kysymykset

Onko oppitunti ”SupervisorJob vs Job: virheiden eristäminen” ilmainen?

Kyllä — voit lukea täällä verkossa kokonaan ilmaiseksi mitkä tahansa Kotlin Academy-oppimispolun 3 oppituntia, myös oppitunnin “SupervisorJob vs Job: virheiden eristäminen”. Sen jälkeen CoddyKit PRO avaa kaikki oppitunnit sekä interaktiiviset harjoitukset sisäänrakennetulla koodieditorilla ja ympäri vuorokauden toimivalla tekoälytuutorilla. Kotlin Academy-kurssilla on yhteensä 4 oppituntia.

Mitä opin oppitunnilla ”SupervisorJob vs Job: virheiden eristäminen”?

Käyttäkää SupervisorJobia estämään yhden lapsen virheen aiheuttama sisarusten peruutus. Harjoittelet Kotlin Academy-aihetta koodilla, jonka suoritat suoraan selaimessa. Ympäri vuorokauden käytettävissä oleva tekoälytuutori vastaa kysymyksiisi oppitunnin aikana.

Tarvitsenko kokemusta aloittaakseni Kotlin Academy-opiskelun?

Aiempi kokemus ei ole tarpeen. CoddyKitin Kotlin Academy-oppimispolku sopii vasta-alkajista edistyneisiin, joten voit aloittaa tästä tai alusta ja edetä omaan tahtiisi. Tämä on oppitunti 1/4.

Kuinka kauan ”SupervisorJob vs Job: virheiden eristäminen”-oppitunnin suorittaminen kestää?

Useimmat CoddyKitin oppitunnit kestävät noin 5–10 minuuttia. Jokainen oppitunti on lyhyt ja interaktiivinen, joten edistyt tasaisesti ja voit jatkaa siitä, mihin jäit – sekä verkossa että sovelluksessa.

Voinko kirjoittaa ja suorittaa koodia tällä Kotlin Academy-oppitunnilla?

Kyllä. Jokainen Kotlin Academy-oppitunti sisältää sisäänrakennetun koodieditorin, joten voit kirjoittaa ja suorittaa oikeaa koodia suoraan selaimessa ja saada välitöntä palautetta tekoälyltä – paikallista asennusta ei tarvita.

Kaikki tämän kurssin oppitunnit

  1. SupervisorJob vs Job: virheiden eristäminen
  2. CoroutineExceptionHandler: maailmanlaajuinen käsittelemätön poikkeusten käsittelijä
  3. async/await-poikkeusten eteneminen
  4. Vikasietoisten korutiiniarkkitehtuurien suunnittelu
← Takaisin: Kotlin Academy