¿Qué sucede con una coroutine cuando ocurre una excepción?
sobes.tech AI
Respuesta de la IA
Cuando ocurre una excepción dentro de una coroutine, la dependencia del tipo de excepción (y la configuración del dispatcher/contexto) determina cómo será manejada.
-
Excepción no controlada: Si la excepción no es capturada dentro de la coroutine, se propaga hacia arriba en la jerarquía de coroutines hasta el
JoboCoroutineScopemás cercano. El comportamiento depende del tipo deJob:Job: Por defecto, cuando ocurre una excepción en una coroutine hija, elJobpadre se cancela, lo que lleva a la cancelación de todas sus demás coroutines hijas. La excepción se propaga hacia arriba.SupervisorJob: ElSupervisorJobpadre no se cancela cuando ocurre una excepción en una coroutine hija. Solo la coroutine en la que ocurrió la error se cancela. Esto es útil cuando quieres que la cancelación de una tarea hija no afecte a las otras.CoroutineScoperaíz: Si la excepción alcanza elCoroutineScoperaíz (por ejemplo,GlobalScopeo un scope creado conCoroutineScopesinJob), se pasa al manejador global de excepcionesCoroutineExceptionHandler. Por defecto, si no hay un manejador registrado, la excepción se registra enSystem.err.
-
Excepción controlada: Si la excepción es capturada con un bloque
try-catchdentro de la coroutine, se maneja localmente y la coroutine continúa ejecutándose después del bloquecatch, si es posible. La excepción no se propaga hacia arriba. -
Excepciones relacionadas con la cancelación (por ejemplo,
CancellationException): Estas excepciones son especiales. Se usan para el mecanismo de cancelación de coroutines y generalmente son ignoradas por la mayoría de los manejadores de excepciones por defecto. No causan una falla fatale en elJobpadre por defecto. -
Excepciones en
async: La coroutine lanzada conasynccoloca la excepción en suDeferred. La excepción solo se propaga cuando se llama a.await()en eseDeferred. Hasta ese momento, la excepción está "oculta".
import kotlinx.coroutines.*
fun main() = runBlocking {
val scope = CoroutineScope(SupervisorJob())
scope.launch {
try {
println("Coroutine 1 started")
delay(100)
throw RuntimeException("Something went wrong in Coroutine 1")
} catch (e: Exception) {
println("Coroutine 1 caught exception: ${e.message}")
}
}
scope.launch {
println("Coroutine 2 started")
delay(500)
println("Coroutine 2 finished")
}
delay(1000) // Esperamos para ver la salida
scope.cancel() // Cancelamos el scope
}
En este ejemplo, la excepción en la Coroutine 1 se captura, y la Coroutine 2 continúa ejecutándose porque se usa SupervisorJob. Si en lugar de SupervisorJob se usara un Job normal, la excepción en la Coroutine 1 provocaría la cancelación de la Coroutine 2.