In this example we have 2 co-routines:

  • First co-routine is going to throw exception after 2 seconds.
  • Second co-routine is processing some unrelated messages every half second.

Once 1st co-routine throws exception:

  • Second co-routine gets Cancellation Exception on invocation of delay() (delay is functions-suspension-point)
  • The exception is rethrown to the parent and the catch block within main() catches the exception.

Code

package com.glassthought.sandbox
 
import gt.sandbox.util.output.Out
import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.CoroutineName
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
 
suspend fun main(): kotlin.Unit {
  val out = Out.standard()
 
  out.info("START")
 
  try {
    val runBlocking = runBlocking {
      launch(CoroutineName("WillFail")) {
        val timeMillis = 2000L
        out.info("This one will throw in $timeMillis ms")
        delay(timeMillis)
        out.warn("OK I am about to throw an exception!")
        throw MyExceptionWillThrowFromCoroutine("I-Failed-In-CoRoutine")
      }
 
      launch(CoroutineName("JustPrints")) {
        (0..10)
          .map { "a-${it}" }
          .forEach {
            out.info(it)
 
            try {
              delay(500)
            } catch (e: CancellationException) {
              val excMsg = e.message ?: e.toString()
              out.warn("I have caught [${e::class.simpleName}/$excMsg], and rethrowing it")
 
              throw e
            }
          }
      }
    }
  } catch (e: Exception) {
    out.error("runBlocking threw an exception! of type=[${e::class.simpleName}] with msg=[${e.message}]")
  }
 
 
  out.info("DONE")
}
 
class MyExceptionWillThrowFromCoroutine(msg: String) : RuntimeException(msg)

Command to reproduce:

gt.sandbox.checkout.commit fc980e0c3d78ab332670 \
&& cd "${GT_SANDBOX_REPO}" \
&& cmd.run.announce "./gradlew run --quiet"

Recorded output of command:

Picked up JAVA_TOOL_OPTIONS: -Dkotlinx.coroutines.debug
Picked up JAVA_TOOL_OPTIONS: -Dkotlinx.coroutines.debug
[INFO][elapsed:   17ms][🥇][🧵][tname:main/tid:1] START
[INFO][elapsed:   49ms][🥇][1️⃣][coroutname:@WillFail#2][tname:main/tid:1] This one will throw in 2000 ms
[INFO][elapsed:   57ms][🥇][2️⃣][coroutname:@JustPrints#3][tname:main/tid:1] a-0
[INFO][elapsed:  558ms][🥇][2️⃣][coroutname:@JustPrints#3][tname:main/tid:1] a-1
[INFO][elapsed: 1058ms][🥇][2️⃣][coroutname:@JustPrints#3][tname:main/tid:1] a-2
[INFO][elapsed: 1558ms][🥇][2️⃣][coroutname:@JustPrints#3][tname:main/tid:1] a-3
[WARN][elapsed: 2054ms][🥇][1️⃣][coroutname:@WillFail#2][tname:main/tid:1] OK I am about to throw an exception!
[WARN][elapsed: 2103ms][🥇][2️⃣][coroutname:@JustPrints#3][tname:main/tid:1] I have caught [JobCancellationException/Parent job is Cancelling], and rethrowing it
[ERROR][elapsed: 2104ms][🥇][🧵][tname:main/tid:1] runBlocking threw an exception! of type=[MyExceptionWillThrowFromCoroutine] with msg=[I-Failed-In-CoRoutine]
[INFO][elapsed: 2104ms][🥇][🧵][tname:main/tid:1] DONE