Cleanup with finally and NonCancellable

finally Runs on Cancel

Because cancellation is an exception, try/finally and use { } work normally: close files, release locks, hide progress bars.

But inside finally of a cancelled coroutine, any suspend call throws CancellationException again. If cleanup must suspend (e.g. save to DB, tell the server), wrap it in withContext(NonCancellable).

Example

Example

import kotlinx.coroutines.*

fun main() = runBlocking {
    val job = launch {
        try {
            repeat(10) { i ->
                println("Uploading part $i")
                delay(100)
            }
        } finally {
            println("finally: hide progress bar")
            try {
                delay(10)          // suspending in a cancelled coroutine
                println("never printed")
            } catch (e: CancellationException) {
                println("finally: plain delay was cancelled")
            }
            withContext(NonCancellable) {
                delay(50)
                println("finally: saved draft to DB (NonCancellable)")
            }
        }
    }
    delay(150)
    job.cancelAndJoin()
    println("Done")
}

Output

Uploading part 0
Uploading part 1
finally: hide progress bar
finally: plain delay was cancelled
finally: saved draft to DB (NonCancellable)
Done

Note: Use NonCancellable only for short cleanup, never with launch(NonCancellable) for normal work: it breaks structured concurrency.