Почему при использовании supervisorScope, CoroutineExceptionHandler не получает ошибку?

Я тестирую всякие примеры касательно exception handling и вот у меня есть очень простой пример

fun main() {
    val handler = CoroutineExceptionHandler { coroutineContext, throwable ->
        println("handled exception: $throwable")
    }

    val scope = CoroutineScope(Job() + handler)

    scope.launch {
        val firstResultDeferred = async {
            println("print FIRST")
            throw RuntimeException()
        }

        val secondResultDeferred = async {
            println("print SECOND")
            "SECOND"
        }

        val thirdResultDeferred = async {
            println("print THIRD")
            "THIRD"
        }

        val firstResult = try {
            firstResultDeferred.await()
        } catch (e: Exception) {
            println("1 exception: $e")
            null
        }

        val secondResult = try {
            secondResultDeferred.await()
        } catch (e: Exception) {
            println("2 exception: $e")
            null
        }

        val thirdResult = try {
            thirdResultDeferred.await()
        } catch (e: Exception) {
            println("3 exception: $e")
            null
        }

        val resultList = listOf(firstResult, secondResult, thirdResult)

        println("RESULT IS: ${resultList.joinToString(", ")}")
    }

    Thread.sleep(2000)
}

Запускается 3 асинка где в первом ошибка, вот такой лог получается

print FIRST
1 exception: java.lang.RuntimeException
2 exception: kotlinx.coroutines.JobCancellationException: Parent job is Cancelling; job=StandaloneCoroutine{Cancelling}@69ea4681
3 exception: kotlinx.coroutines.JobCancellationException: Parent job is Cancelling; job=StandaloneCoroutine{Cancelling}@69ea4681
RESULT IS: null, null, null
handled exception: java.lang.RuntimeException

Process finished with exit code 0

Вроде как все предсказуемо, мы видим первый принт print FIRST потом ошибка которая отлавливается try/catch -> 1 exception: java.lang.RuntimeException, поскольку это обычный Job то два других асинка отменяются и это тоже отлавливается.

Интересный момент в том, что сама ошибка которая происходит в первом асинке передается вверх по иерархии в launch где отлавливается handlerом и мы видим последний лог handled exception: java.lang.RuntimeException. Тут вроде как все логично получается.

Но если я хочу, чтоб при ошибке в одном асинке други продолжали свою работу, мне нужно поменять скоуп на supervisorScope, вот так

fun main() {
    val handler = CoroutineExceptionHandler { coroutineContext, throwable ->
        println("handled exception: $throwable")
    }

    val scope = CoroutineScope(Job() + handler)

    scope.launch {
        supervisorScope {
            val firstResultDeferred = async {
                println("print FIRST")
                throw RuntimeException()
            }

            val secondResultDeferred = async {
                println("print SECOND")
                "SECOND"
            }

            val thirdResultDeferred = async {
                println("print THIRD")
                "THIRD"
            }

            val firstResult = try {
                firstResultDeferred.await()
            } catch (e: Exception) {
                println("1 exception: $e")
                null
            }

            val secondResult = try {
                secondResultDeferred.await()
            } catch (e: Exception) {
                println("2 exception: $e")
                null
            }

            val thirdResult = try {
                thirdResultDeferred.await()
            } catch (e: Exception) {
                println("3 exception: $e")
                null
            }

            val resultList = listOf(firstResult, secondResult, thirdResult)

            println("RESULT IS: ${resultList.joinToString(", ")}")
        }
    }

    Thread.sleep(2000)
}

и лог получается вот такой

print FIRST
print SECOND
1 exception: java.lang.RuntimeException
print THIRD
RESULT IS: null, SECOND, THIRD

Process finished with exit code 0

Вроде тоже все предсказуемо и дейсвительно в результате два оставшихся асинка дорабатывают, НО вопрос - куда делась вот эта строка - handled exception: java.lang.RuntimeException, почему ошибка не предается вверх к launch и не отлавливается хендлером?


Ответы (0 шт):