0Pricing
Kotlin Academy · Lección

CoroutineExceptionHandler: gestor global de excepciones no capturadas

Instale un CoroutineExceptionHandler para registrar o recuperar excepciones no gestionadas.

CoroutineExceptionHandler: gestor global de excepciones no capturadas es una lección gratuita de Kotlin Academy en CoddyKit. Esta es la lección 2 de 4. Puedes leer la lección completa abajo gratuitamente — luego la practicas en el navegador con un editor de código integrado y un tutor de IA 24/7. Forma parte de la ruta de aprendizaje de Kotlin Academy, y tu progreso se sincroniza en la web y la app de CoddyKit. El curso de Kotlin Academy incluye 4 lecciones en total.

¿Qué es CoroutineExceptionHandler?

CoroutineExceptionHandler es un elemento del contexto que gestiona las excepciones no capturadas de las corrutinas que no tienen un manejador catch. Actúa como último recurso.

import kotlinx.coroutines.*
val handler = CoroutineExceptionHandler { context, exception ->
    println("Caught unhandled: ${exception.message}")
}
fun main() = runBlocking {
    val scope = CoroutineScope(Dispatchers.Default + handler)
    scope.launch { throw RuntimeException("oops") }
    delay(100)
}

Solo para corrutinas raíz

CoroutineExceptionHandler solo captura excepciones de corrutinas raíz (iniciadas directamente en un scope). Las corrutinas hijas propagan las excepciones a su padre, no al manejador.

import kotlinx.coroutines.*
val handler = CoroutineExceptionHandler { _, e -> println("Handler: ${e.message}") }
fun main() = runBlocking {
    // Root coroutine — handler fires:
    CoroutineScope(handler).launch {
        throw RuntimeException("root error")
    }
    delay(100)
    // NOT handler (child of coroutineScope):
    // launch { launch { throw RuntimeException() } }
}

No suprime la excepción

El manejador se invoca después de que la excepción ya haya cancelado la corrutina. Sirve para registrar información, informar de errores o realizar tareas de limpieza, no para reanudar la ejecución.

import kotlinx.coroutines.*
val handler = CoroutineExceptionHandler { _, e ->
    println("[CrashReport] ${e::class.simpleName}: ${e.message}")
    // send to Crashlytics, Sentry, etc.
}
fun main() = runBlocking {
    CoroutineScope(SupervisorJob() + handler).apply {
        launch { throw IllegalStateException("state error") }
        launch { delay(100); println("still alive") }
        delay(200)
        cancel()
    }
}

Manejador + SupervisorJob

La combinación de SupervisorJob + CoroutineExceptionHandler es el patrón estándar para scopes de larga duración: los hijos fallan de forma independiente y los fallos no gestionados se registran.

import kotlinx.coroutines.*
class AppScope {
    private val handler = CoroutineExceptionHandler { _, e ->
        println("Uncaught: ${e.message}")
    }
    val scope = CoroutineScope(SupervisorJob() + Dispatchers.Default + handler)
}
fun main() = runBlocking {
    val app = AppScope()
    app.scope.launch { throw RuntimeException("task failed") }
    app.scope.launch { delay(100); println("other task ok") }
    delay(200)
    app.scope.cancel()
}

Manejador con async

En async, las excepciones se almacenan en Deferred y se lanzan en await(). El manejador NO se activa para async a menos que no se espere el deferred.

import kotlinx.coroutines.*
val handler = CoroutineExceptionHandler { _, e -> println("Handler: ${e.message}") }
fun main() = runBlocking {
    val scope = CoroutineScope(SupervisorJob() + handler)
    val deferred = scope.async { throw RuntimeException("async error") }
    try {
        deferred.await()  // exception thrown here
    } catch (e: RuntimeException) {
        println("Caught from await: ${e.message}")
    }
    delay(50)
    scope.cancel()
}

Comparación con Thread.UncaughtExceptionHandler

A diferencia de UncaughtExceptionHandler de Java, el manejador de Kotlin forma parte del contexto de la corrutina y solo se aplica a las corrutinas que se ejecutan dentro de ese scope.

import kotlinx.coroutines.*
// Java style (applies to threads):
Thread.setDefaultUncaughtExceptionHandler { t, e ->
    println("Thread ${t.name} threw: ${e.message}")
}
// Kotlin coroutine style (applies to coroutines in scope):
val handler = CoroutineExceptionHandler { _, e ->
    println("Coroutine threw: ${e.message}")
}
fun main() = runBlocking { println("Handlers target different concurrency models") }

Patrón de registro con MDC

En aplicaciones de servidor, el manejador puede capturar información del contexto de la corrutina (como los identificadores de solicitud) para realizar un registro estructurado antes de reenviarla al framework de registro.

import kotlinx.coroutines.*
val handler = CoroutineExceptionHandler { ctx, e ->
    val jobName = ctx[CoroutineName]?.name ?: "unknown"
    println("[${jobName}] ERROR: ${e.message}")
}
fun main() = runBlocking {
    CoroutineScope(SupervisorJob() + handler).launch(CoroutineName("DataLoader")) {
        throw RuntimeException("fetch failed")
    }
    delay(100)
}

Integración con informes de errores

Use el manejador para reenviar las excepciones no capturadas a servicios de informes de errores como Firebase Crashlytics o Sentry.

import kotlinx.coroutines.*
object CrashReporter {
    fun record(e: Throwable) = println("[Crashlytics] ${e.message}")
}
val handler = CoroutineExceptionHandler { _, e ->
    if (e !is CancellationException) CrashReporter.record(e)
}
val appScope = CoroutineScope(SupervisorJob() + Dispatchers.Default + handler)
fun main() = runBlocking {
    appScope.launch { throw RuntimeException("unhandled in production") }
    delay(100)
    appScope.cancel()
}

Herencia del manejador

El manejador del contexto padre NO se hereda automáticamente en las corrutinas hijas. Debe estar en el contexto de la corrutina raíz para activarse.

import kotlinx.coroutines.*
val handler = CoroutineExceptionHandler { _, e -> println("Handler: ${e.message}") }
fun main() = runBlocking {
    // Handler only fires at root level:
    CoroutineScope(SupervisorJob() + handler).launch {
        // Child of root — exception propagates to root handler:
        launch { throw RuntimeException("nested") }
    }
    delay(100)
}

Resumen de buenas prácticas

Instale siempre un CoroutineExceptionHandler en los scopes de nivel de aplicación o de funcionalidad. Registre toda excepción que no sea de cancelación. Nunca dependa de él para controlar el flujo; solo sirve para la observabilidad.

import kotlinx.coroutines.*
val globalHandler = CoroutineExceptionHandler { ctx, e ->
    if (e !is CancellationException) {
        println("[ERROR] ${ctx[CoroutineName]?.name}: ${e.message}")
    }
}
val appScope = CoroutineScope(SupervisorJob() + Dispatchers.Default + globalHandler)
fun main() = runBlocking {
    appScope.launch(CoroutineName("Auth")) { throw RuntimeException("token expired") }
    delay(100); appScope.cancel()
}

Comprobación rápida

¿Para qué tipo de corrutina NO se activa automáticamente CoroutineExceptionHandler?

Resumen

CoroutineExceptionHandler es un observador de último recurso para las excepciones no capturadas en corrutinas raíz. Combínelo con SupervisorJob para scopes de larga duración. Úselo para registrar información e informar de errores, nunca para controlar el flujo.

Preguntas frecuentes

¿La lección «CoroutineExceptionHandler: gestor global de excepciones no capturadas» es gratis?

Sí — el texto completo de «CoroutineExceptionHandler: gestor global de excepciones no capturadas» es gratis para leer aquí en la web. Para practicarla de forma interactiva (editor de código integrado y tutor de IA 24/7) y desbloquear el resto del curso de Kotlin Academy, actualiza a CoddyKit PRO. El curso de Kotlin Academy incluye 4 lecciones en total.

¿Qué aprenderé en «CoroutineExceptionHandler: gestor global de excepciones no capturadas»?

Instale un CoroutineExceptionHandler para registrar o recuperar excepciones no gestionadas. Practicas Kotlin Academy con código real que ejecutas directamente en el navegador, y un tutor de IA 24/7 responde tus preguntas mientras trabajas en la lección.

¿Necesito experiencia previa para empezar Kotlin Academy?

No se requiere experiencia previa. Kotlin Academy en CoddyKit está estructurado para principiantes hasta estudiantes avanzados, así que puedes empezar aquí o desde el inicio y avanzar a tu ritmo. Esta es la lección 2 de 4.

¿Cuánto tiempo toma la lección «CoroutineExceptionHandler: gestor global de excepciones no capturadas»?

La mayoría de las lecciones de CoddyKit toman alrededor de 5–10 minutos. Cada una es compacta e interactiva, así que avanzas constantemente y retomas exactamente por donde dejaste en la web y la app.

¿Puedo escribir y ejecutar código en esta lección de Kotlin Academy?

Sí. Cada lección de Kotlin Academy incluye un editor de código integrado, así que escribes y ejecutas código real directamente en tu navegador y obtienes retroalimentación instantánea de IA — sin configuración local necesaria.

Todas las lecciones de este curso

  1. SupervisorJob frente a Job: aislamiento de fallos
  2. CoroutineExceptionHandler: gestor global de excepciones no capturadas
  3. Propagación de excepciones en async/await
  4. Diseñar arquitecturas de corrutinas resilientes
← Volver a Kotlin Academy