Sobes.tech
Middle

Que se passe-t-il avec une coroutine lorsqu'une exception se produit?

sobes.tech IA

Réponse de l'IA

Lorsqu'une exception se produit à l'intérieur d'une coroutine, la dépendance au type d'exception (et aux paramètres du dispatcher/contexte) détermine comment elle sera traitée.

  • Exception non gérée : Si l'exception n'est pas capturée à l'intérieur de la coroutine, elle se propage vers le haut dans la hiérarchie des coroutines jusqu'au Job ou CoroutineScope le plus proche. Le comportement dépend du type de Job:

    • Job : Par défaut, lorsqu'une exception se produit dans une coroutine fille, le Job parent est annulé, ce qui entraîne l'annulation de toutes ses autres coroutines filles. L'exception est propagée vers le haut.
    • SupervisorJob : Le SupervisorJob parent n'est pas annulé lorsqu'une exception se produit dans une coroutine fille. Seule la coroutine dans laquelle l'exception s'est produite est annulée. Cela est utile lorsque vous souhaitez que l'annulation d'une tâche fille n'affecte pas les autres.
    • CoroutineScope racine : Si l'exception atteint le CoroutineScope racine (par exemple, GlobalScope ou un scope créé avec CoroutineScope sans Job), elle est transmise au gestionnaire global d'exceptions CoroutineExceptionHandler. Par défaut, si aucun gestionnaire n'est enregistré, l'exception est enregistrée dans System.err.
  • Exception capturée : Si l'exception est capturée à l'aide d'un bloc try-catch à l'intérieur de la coroutine, elle est traitée localement, et la coroutine continue son exécution après le bloc catch, si cela est possible. L'exception n'est pas propagée vers le haut.

  • Exceptions liées à l'annulation (par exemple, CancellationException) : Ces exceptions sont particulières. Elles sont utilisées pour le mécanisme d'annulation des coroutines et sont généralement ignorées par la plupart des gestionnaires d'exceptions par défaut. Elles ne provoquent pas d'échec fatale du Job parent par défaut.

  • Exceptions dans async : La coroutine lancée via async place l'exception dans son Deferred. L'exception n'est propagée que lors de l'appel de .await() sur ce Deferred. Jusqu'à ce moment, l'exception est "cachée".

import kotlinx.coroutines.*

fun main() = runBlocking {
    val scope = CoroutineScope(SupervisorJob())

    scope.launch {
        try {
            println("Coroutine 1 démarrée")
            delay(100)
            throw RuntimeException("Quelque chose a mal tourné dans Coroutine 1")
        } catch (e: Exception) {
            println("Coroutine 1 a capturé l'exception : ${e.message}")
        }
    }

    scope.launch {
        println("Coroutine 2 démarrée")
        delay(500)
        println("Coroutine 2 terminée")
    }

    delay(1000) // Attendre pour voir la sortie
    scope.cancel() // Annuler le scope
}

Dans cet exemple, l'exception dans la Coroutine 1 est capturée, et la Coroutine 2 continue son exécution car SupervisorJob est utilisé. Si un Job normal était utilisé à la place, l'exception dans la Coroutine 1 entraînerait l'annulation de la Coroutine 2.