Cleanup with finally and NonCancellable
Release resources in cancelled coroutines using finally and withContext(NonCancellable).
Cancellation and finally
When a coroutine is cancelled, suspension points throw CancellationException. Code in finally blocks always runs — but finally itself runs in a cancelled coroutine context.
import kotlinx.coroutines.*
fun main() = runBlocking {
val job = launch {
try {
delay(1000)
} finally {
println("finally: cleaning up")
}
}
delay(50)
job.cancel()
job.join()
}Problem: Suspension in finally
If you try to delay or do another suspension inside finally of a cancelled coroutine, it throws immediately because the context is already cancelled.
import kotlinx.coroutines.*
fun main() = runBlocking {
val job = launch {
try {
delay(1000)
} finally {
// delay(100) // throws CancellationException here!
println("Sync cleanup OK; async cleanup needs NonCancellable")
}
}
delay(50); job.cancel(); job.join()
}All lessons in this course
- Cooperative Cancellation: isActive and ensureActive
- withTimeout and withTimeoutOrNull
- Cleanup with finally and NonCancellable
- Cancellation Propagation in Coroutine Hierarchies