Skip to content

Instantly share code, notes, and snippets.

@erikhuizinga
Created June 30, 2020 16:42
Show Gist options
  • Save erikhuizinga/c82a404d76c52b6959248ccbb377999f to your computer and use it in GitHub Desktop.
Save erikhuizinga/c82a404d76c52b6959248ccbb377999f to your computer and use it in GitHub Desktop.
Demo of Kotlin coroutine crash machinery
import kotlinx.coroutines.CoroutineExceptionHandler
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Job
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.async
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
fun main() =
try {
demo1JustCrash()
// demo2JustCrash()
// demo3JustCatch()
// demo4AwaitCrashOrCancel()
// demo5AwaitCrashOrCancel()
// demo6AwaitHandleCrash()
println()
println("Your app finished successfully! ๐ŸŽ‰")
} catch (t: Throwable) {
println()
println("Your app crashed! ๐Ÿ˜ฐ")
println(t)
println()
println(
"""
๐Ÿ‘พ ๐Ÿ‘พ ๐Ÿ‘พ ๐Ÿ‘พ
๐Ÿ‘พ GAME OVER ๐Ÿ‘พ
๐Ÿ‘พ ๐Ÿ‘พ ๐Ÿ‘พ ๐Ÿ‘พ
""".trimIndent()
)
}
suspend fun crash(): Any? {
delay(500)
throw Throwable("๐Ÿ”ฅ")
}
fun handle(throwable: Throwable) = println("OK, handled: $throwable")
fun demo1JustCrash() {
printDemo(1)
val scope = CoroutineScope(Job())
val job = scope.launch { crash() }
// Ensure we don't continue before all coroutines complete
runBlocking { job.join() }
/* Where did the exception go? Who caught it? */
}
fun demo2JustCrash() {
printDemo(2)
val scope = CoroutineScope(Job())
val deferred = scope.async { crash() }
// Ensure we don't continue before all coroutines complete
runBlocking { deferred.await() }
/* Where did the exception go? Who caught it? */
}
fun demo3JustCatch() {
printDemo(3)
val scope = CoroutineScope(Job())
val job = scope.launch {
// Just catch inside your coroutine body
try {
crash()
} catch (t: Throwable) {
handle(t)
}
}
val deferred = scope.async {
// Just catch inside your coroutine body
try {
crash()
} catch (t: Throwable) {
handle(t)
}
}
// Ensure we don't continue before all coroutines complete
runBlocking {
job.join()
deferred.await()
}
}
fun demo4AwaitCrashOrCancel() {
printDemo(4)
val parentJob = Job()
val scope = CoroutineScope(parentJob)
// Obtain a future value
val deferred = scope.async { crash() }
// Await it in another coroutine
val awaitJob = scope.launch { deferred.await() }
// Ensure we don't continue before all coroutines complete
runBlocking { awaitJob.join() }
/* Where did the exception go? Who caught it? */
/* What will the following print? */
println("isActive = ${parentJob.isActive}")
println("isCancelled = ${parentJob.isCancelled}")
println("isCompleted = ${parentJob.isCompleted}")
}
fun demo5AwaitCrashOrCancel() {
printDemo(5)
val parentJob = SupervisorJob()
val scope = CoroutineScope(parentJob)
// Obtain a future value
val deferred = scope.async { crash() }
// Await it in another coroutine
val awaitJob = scope.launch { deferred.await() }
// Ensure we don't continue before all coroutines complete
runBlocking { awaitJob.join() }
/* Where did the exception go? Who caught it? */
/* What will the following print? */
println("isActive = ${parentJob.isActive}")
println("isCancelled = ${parentJob.isCancelled}")
println("isCompleted = ${parentJob.isCompleted}")
/* What will the following print? */
println("isActive = ${awaitJob.isActive}")
println("isCancelled = ${awaitJob.isCancelled}")
println("isCompleted = ${awaitJob.isCompleted}")
}
fun demo6AwaitHandleCrash() {
printDemo(6)
val parentJob = SupervisorJob()
val coroutineExceptionHandler = CoroutineExceptionHandler { _, exception ->
println("Coroutine exception handler: $exception")
}
val scope = CoroutineScope(parentJob + coroutineExceptionHandler)
// Obtain a future value
val deferred = scope.async { crash() }
// Await it in another coroutine
val awaitJob = scope.launch { deferred.await() }
// Ensure we don't continue before all coroutines complete
runBlocking { awaitJob.join() }
/* Where did the exception go? Who caught it? */
/* What will the following print? */
println("isActive = ${parentJob.isActive}")
println("isCancelled = ${parentJob.isCancelled}")
println("isCompleted = ${parentJob.isCompleted}")
/* What will the following print? */
println("isActive = ${awaitJob.isActive}")
println("isCancelled = ${awaitJob.isCancelled}")
println("isCompleted = ${awaitJob.isCompleted}")
}
private fun printDemo(n: Int) {
println()
println("Demo $n")
println()
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment