withCleanup

suspend fun <T> withCleanup(cleanup: suspend () -> Unit, block: suspend () -> T): T(source)

Runs block and then always runs cleanup inside withContext(NonCancellable), so cleanup is allowed to suspend even when the coroutine is already cancelled.

cleanup runs after block succeeds, throws, or is cancelled. If block failed and cleanup also throws, the exception from block is kept and the cleanup exception is attached with addSuppressed. If only cleanup throws, that exception propagates.

Example:

withCleanup(cleanup = { session.close() }) {
session.send(request)
}

Cancellation of block is not swallowed: after cleanup has run, the original CancellationException is rethrown like any other exception from block.

Rule: CANCEL_004 (cleanup in finally that suspends must use NonCancellable). See docs/BEST_PRACTICES_COROUTINES.md.

Requires opting in to ExperimentalStructuredCoroutines.

Return

the value returned by block.

Parameters

cleanup

suspending cleanup, always executed in a NonCancellable context.

block

the main work.

See also

Throws

whatever block threw (including CancellationException), or the exception from cleanup when block succeeded.