Extension methods for handling cooperative cancellation
The following extension methods are concise way to avoid having to write separate catch for cancellation exception over and over again.
/**
* Executes a suspend function, catching all exceptions except [CancellationException].
*
* Does not catch [Error] or other [Throwable] types that don't extend [Exception].
* Cancellation exceptions are always rethrown to preserve structured concurrency.
*
* Example:
* ```
* suspend {
* syncData()
* }.catching { e ->
* logger.error("Sync failed", e)
* }
* ```
*/
suspend fun (suspend () -> Unit).catching(
onError: suspend (Exception) -> Unit
) {
try {
this()
} catch (e: CancellationException) {
throw e
} catch (e: Exception) {
onError(e)
}
}
/**
* Executes a suspend function that returns a value, catching all exceptions except [CancellationException].
*
* Cancellation exceptions are always rethrown to preserve structured concurrency.
*
* @param onError Handler invoked when an exception occurs. Must return a fallback value of type [T].
* @return The result of the block, or the fallback value from [onError] if an exception occurs.
*
* Example:
* ```
* val data = suspend {
* fetchUserData()
* }.catchingReturns { e ->
* logger.error("Fetch failed", e)
* emptyList() // fallback value
* }
* ```
*/
suspend fun <T> (suspend () -> T).catchingReturns(
onError: suspend (Exception) -> T
): T = try {
this()
} catch (e: CancellationException) {
throw e
} catch (e: Exception) {
onError(e)
}
Backlinks