@@ -414,8 +413,8 @@ Second child is cancelled because supervisor is cancelled
#### Supervision scope
-For *scoped* concurrency [supervisorScope] can be used instead of [coroutineScope] for the same purpose. It propagates cancellation
-only in one direction and cancels all children only if it has failed itself. It also waits for all children before completion
+For _scoped_ concurrency [supervisorScope] can be used instead of [coroutineScope] for the same purpose. It propagates cancellation
+in one direction only and cancels all children only if it has failed itself. It also waits for all children before completion
just like [coroutineScope] does.
@@ -463,8 +462,11 @@ Caught assertion error
#### Exceptions in supervised coroutines
Another crucial difference between regular and supervisor jobs is exception handling.
-Every child should handle its exceptions by itself via exception handling mechanisms.
+Every child should handle its exceptions by itself via exception handling mechanism.
This difference comes from the fact that child's failure is not propagated to the parent.
+It means that coroutines launched directly inside [supervisorScope] _do_ use the [CoroutineExceptionHandler]
+that is installed in their scope in the same way as root coroutines do
+(see [CoroutineExceptionHandler](#coroutineexceptionhandler) section for details).
@@ -474,7 +476,7 @@ import kotlinx.coroutines.*
fun main() = runBlocking {
val handler = CoroutineExceptionHandler { _, exception ->
- println("Caught $exception")
+ println("CoroutineExceptionHandler got $exception")
}
supervisorScope {
val child = launch(handler) {
@@ -496,7 +498,7 @@ The output of this code is:
```text
Scope is completing
Child throws an exception
-Caught java.lang.AssertionError
+CoroutineExceptionHandler got java.lang.AssertionError
Scope is completed
```
diff --git a/kotlinx-coroutines-core/jvm/test/guide/example-exceptions-01.kt b/kotlinx-coroutines-core/jvm/test/guide/example-exceptions-01.kt
index 34d7b68c82..e08ddd0811 100644
--- a/kotlinx-coroutines-core/jvm/test/guide/example-exceptions-01.kt
+++ b/kotlinx-coroutines-core/jvm/test/guide/example-exceptions-01.kt
@@ -8,13 +8,13 @@ package kotlinx.coroutines.guide.exampleExceptions01
import kotlinx.coroutines.*
fun main() = runBlocking {
- val job = GlobalScope.launch {
+ val job = GlobalScope.launch { // root coroutine with launch
println("Throwing exception from launch")
throw IndexOutOfBoundsException() // Will be printed to the console by Thread.defaultUncaughtExceptionHandler
}
job.join()
println("Joined failed job")
- val deferred = GlobalScope.async {
+ val deferred = GlobalScope.async { // root coroutine with async
println("Throwing exception from async")
throw ArithmeticException() // Nothing is printed, relying on user to call await
}
diff --git a/kotlinx-coroutines-core/jvm/test/guide/example-exceptions-02.kt b/kotlinx-coroutines-core/jvm/test/guide/example-exceptions-02.kt
index 5242ca1a00..67fdaa7177 100644
--- a/kotlinx-coroutines-core/jvm/test/guide/example-exceptions-02.kt
+++ b/kotlinx-coroutines-core/jvm/test/guide/example-exceptions-02.kt
@@ -9,7 +9,7 @@ import kotlinx.coroutines.*
fun main() = runBlocking {
val handler = CoroutineExceptionHandler { _, exception ->
- println("Caught $exception")
+ println("CoroutineExceptionHandler got $exception")
}
val job = GlobalScope.launch(handler) { // root coroutine, running in GlobalScope
throw AssertionError()
diff --git a/kotlinx-coroutines-core/jvm/test/guide/example-exceptions-04.kt b/kotlinx-coroutines-core/jvm/test/guide/example-exceptions-04.kt
index e1fc22d725..9c9b43d22e 100644
--- a/kotlinx-coroutines-core/jvm/test/guide/example-exceptions-04.kt
+++ b/kotlinx-coroutines-core/jvm/test/guide/example-exceptions-04.kt
@@ -9,7 +9,7 @@ import kotlinx.coroutines.*
fun main() = runBlocking {
val handler = CoroutineExceptionHandler { _, exception ->
- println("Caught $exception")
+ println("CoroutineExceptionHandler got $exception")
}
val job = GlobalScope.launch(handler) {
launch { // the first child
diff --git a/kotlinx-coroutines-core/jvm/test/guide/example-exceptions-05.kt b/kotlinx-coroutines-core/jvm/test/guide/example-exceptions-05.kt
index e97572aba8..04f9385f06 100644
--- a/kotlinx-coroutines-core/jvm/test/guide/example-exceptions-05.kt
+++ b/kotlinx-coroutines-core/jvm/test/guide/example-exceptions-05.kt
@@ -12,19 +12,19 @@ import java.io.*
fun main() = runBlocking {
val handler = CoroutineExceptionHandler { _, exception ->
- println("Caught $exception with suppressed ${exception.suppressed.contentToString()}")
+ println("CoroutineExceptionHandler got $exception with suppressed ${exception.suppressed.contentToString()}")
}
val job = GlobalScope.launch(handler) {
launch {
try {
- delay(Long.MAX_VALUE)
+ delay(Long.MAX_VALUE) // it gets cancelled when another sibling fails with IOException
} finally {
- throw ArithmeticException()
+ throw ArithmeticException() // the second exception
}
}
launch {
delay(100)
- throw IOException()
+ throw IOException() // the first exception
}
delay(Long.MAX_VALUE)
}
diff --git a/kotlinx-coroutines-core/jvm/test/guide/example-exceptions-06.kt b/kotlinx-coroutines-core/jvm/test/guide/example-exceptions-06.kt
index eec27840e5..5a5b276bc3 100644
--- a/kotlinx-coroutines-core/jvm/test/guide/example-exceptions-06.kt
+++ b/kotlinx-coroutines-core/jvm/test/guide/example-exceptions-06.kt
@@ -10,13 +10,13 @@ import java.io.*
fun main() = runBlocking {
val handler = CoroutineExceptionHandler { _, exception ->
- println("Caught original $exception")
+ println("CoroutineExceptionHandler got $exception")
}
val job = GlobalScope.launch(handler) {
- val inner = launch {
+ val inner = launch { // all this stack of coroutines will get cancelled
launch {
launch {
- throw IOException()
+ throw IOException() // the original exception
}
}
}
@@ -24,7 +24,7 @@ fun main() = runBlocking {
inner.join()
} catch (e: CancellationException) {
println("Rethrowing CancellationException with original cause")
- throw e
+ throw e // cancellation exception is rethrown, yet the original IOException gets to the handler
}
}
job.join()
diff --git a/kotlinx-coroutines-core/jvm/test/guide/example-supervision-03.kt b/kotlinx-coroutines-core/jvm/test/guide/example-supervision-03.kt
index b32a004639..5efbe69146 100644
--- a/kotlinx-coroutines-core/jvm/test/guide/example-supervision-03.kt
+++ b/kotlinx-coroutines-core/jvm/test/guide/example-supervision-03.kt
@@ -10,7 +10,7 @@ import kotlinx.coroutines.*
fun main() = runBlocking {
val handler = CoroutineExceptionHandler { _, exception ->
- println("Caught $exception")
+ println("CoroutineExceptionHandler got $exception")
}
supervisorScope {
val child = launch(handler) {
diff --git a/kotlinx-coroutines-core/jvm/test/guide/test/ExceptionsGuideTest.kt b/kotlinx-coroutines-core/jvm/test/guide/test/ExceptionsGuideTest.kt
index 4a140208f9..21d2c73b1b 100644
--- a/kotlinx-coroutines-core/jvm/test/guide/test/ExceptionsGuideTest.kt
+++ b/kotlinx-coroutines-core/jvm/test/guide/test/ExceptionsGuideTest.kt
@@ -22,7 +22,7 @@ class ExceptionsGuideTest {
@Test
fun testExampleExceptions02() {
test("ExampleExceptions02") { kotlinx.coroutines.guide.exampleExceptions02.main() }.verifyLines(
- "Caught java.lang.AssertionError"
+ "CoroutineExceptionHandler got java.lang.AssertionError"
)
}
@@ -41,14 +41,14 @@ class ExceptionsGuideTest {
"Second child throws an exception",
"Children are cancelled, but exception is not handled until all children terminate",
"The first child finished its non cancellable block",
- "Caught java.lang.ArithmeticException"
+ "CoroutineExceptionHandler got java.lang.ArithmeticException"
)
}
@Test
fun testExampleExceptions05() {
test("ExampleExceptions05") { kotlinx.coroutines.guide.exampleExceptions05.main() }.verifyLines(
- "Caught java.io.IOException with suppressed [java.lang.ArithmeticException]"
+ "CoroutineExceptionHandler got java.io.IOException with suppressed [java.lang.ArithmeticException]"
)
}
@@ -56,7 +56,7 @@ class ExceptionsGuideTest {
fun testExampleExceptions06() {
test("ExampleExceptions06") { kotlinx.coroutines.guide.exampleExceptions06.main() }.verifyLines(
"Rethrowing CancellationException with original cause",
- "Caught original java.io.IOException"
+ "CoroutineExceptionHandler got java.io.IOException"
)
}
@@ -85,7 +85,7 @@ class ExceptionsGuideTest {
test("ExampleSupervision03") { kotlinx.coroutines.guide.exampleSupervision03.main() }.verifyLines(
"Scope is completing",
"Child throws an exception",
- "Caught java.lang.AssertionError",
+ "CoroutineExceptionHandler got java.lang.AssertionError",
"Scope is completed"
)
}