kotlinintermediate
Coroutine Timeouts and Cancellation
Control coroutine lifecycle: withTimeout, withTimeoutOrNull, isActive checking, and cooperative cancellation.
kotlinPress ⌘/Ctrl + Shift + C to copy
import kotlinx.coroutines.*
fun main() = runBlocking {
// withTimeout — throws TimeoutCancellationException
println("--- withTimeout ---")
try {
withTimeout(200) {
repeat(10) { i ->
println("Working $i...")
delay(100)
}
}
} catch (e: TimeoutCancellationException) {
println("Timed out: ${e.message}")
}
// withTimeoutOrNull — returns null on timeout
println("\n--- withTimeoutOrNull ---")
val result = withTimeoutOrNull(200) {
delay(500)
"completed"
}
println("Result: $result") // null
val fast = withTimeoutOrNull(200) {
delay(50)
"fast result"
}
println("Fast: $fast") // fast result
// Cooperative cancellation — check isActive
println("\n--- Cooperative ---")
val cpuJob = launch(Dispatchers.Default) {
var count = 0L
while (isActive) { // cooperative check
count++
if (count % 1_000_000 == 0L) {
println("Count: $count")
yield() // or ensureActive()
}
}
println("CPU work cancelled at $count")
}
delay(50)
cpuJob.cancelAndJoin()
// Cancellation with cleanup
println("\n--- Cleanup ---")
val resource = launch {
try {
println("Acquired resource")
delay(Long.MAX_VALUE) // suspended
} catch (e: CancellationException) {
println("Cancellation received")
throw e
} finally {
withContext(NonCancellable) {
println("Releasing resource...")
delay(100) // cleanup allowed
println("Resource released")
}
}
}
delay(50)
resource.cancelAndJoin()
// Race — first result wins
println("\n--- Race ---")
suspend fun fetchFromServer(name: String, delayMs: Long): String {
delay(delayMs)
return "$name responded"
}
val winner = select<String> {
async { fetchFromServer("Server-A", 300) }.onAwait { it }
async { fetchFromServer("Server-B", 100) }.onAwait { it }
async { fetchFromServer("Server-C", 200) }.onAwait { it }
}
println("Winner: $winner")
// Timeout with fallback
println("\n--- Timeout fallback ---")
suspend fun fetchWithFallback(): String {
return withTimeoutOrNull(100) {
delay(200) // too slow
"primary data"
} ?: run {
println("Primary timed out, using fallback")
"fallback data"
}
}
println("Data: ${fetchWithFallback()}")
// Deadlined scope
println("\n--- Deadline ---")
val deadline = System.currentTimeMillis() + 300
coroutineScope {
val tasks = (1..5).map { i ->
async {
val remaining = deadline - System.currentTimeMillis()
withTimeoutOrNull(remaining.coerceAtLeast(0)) {
delay(i * 100L)
"Task $i done"
} ?: "Task $i: timed out"
}
}
tasks.map { it.await() }.forEach { println(it) }
}
}Use Cases
- API call timeout handling
- Cooperative cancellation in CPU-bound work
- Race condition patterns for redundancy
Tags
Related Snippets
Similar patterns you can reuse in the same workflow.
kotlinintermediate
Coroutines — launch, async, and Structured Concurrency
Write concurrent code with Kotlin coroutines: launch, async/await, structured concurrency, and dispatchers.
Best for: Parallel API calls in backend services
#kotlin#coroutines
kotlinintermediate
Flow — Reactive Streams with Coroutines
Build reactive pipelines with Kotlin Flow: emit, collect, transform, combine, and error handling.
Best for: Streaming data processing pipelines
#kotlin#flow
kotlinadvanced
Channels — Producer-Consumer with Coroutines
Communicate between coroutines with Channels: produce, actor pattern, fan-out/fan-in, and select.
Best for: Producer-consumer patterns in coroutines
#kotlin#channels
kotlinadvanced
Coroutine Mutex and Shared Mutable State
Safely manage shared state across coroutines: Mutex, atomic operations, and actor-based state.
Best for: Thread-safe counters and accumulators
#kotlin#coroutines