0Pricing
Kotlin Academy · Lesson

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

  1. Cooperative Cancellation: isActive and ensureActive
  2. withTimeout and withTimeoutOrNull
  3. Cleanup with finally and NonCancellable
  4. Cancellation Propagation in Coroutine Hierarchies
← Back to Kotlin Academy