withTimeout
Shorthand form for calling withTimeout with a Duration timeout of timeMillis milliseconds. Please see the overload accepting a Duration for details.
Note: the behavior of this function can be different from withTimeout if timeMillis is greater than
Long.MAX_VALUE / 2milliseconds.
Calls the given suspending block with the specified timeout, suspends until it completes, and returns the result.
If the block execution times out, it is cancelled with a TimeoutCancellationException. If the timeout is non-positive, this happens immediately, and the block is not executed.
Cancellation on timeout runs concurrently the code running in the block and may happen at any time, even after the block finishes executing but before the caller gets resumed with the result.
Implementation note: how the time is tracked exactly is an implementation detail of the CoroutineDispatcher in the currentCoroutineContext.
Structured Concurrency
withTimeout behaves like coroutineScope, as it, too, creates a new lexically scoped child coroutine. Refer to the documentation of coroutineScope for details.
Pitfalls
Cancellation is cooperative
withTimeout will not automatically stop all code inside it from being executed once the timeout gets triggered. It only cancels the running block, but it's up to the block to notice that it was cancelled, for example, by suspending or checking isActive.
This JVM code will run to completion, taking 10 seconds to do so:
withTimeout(1.seconds) {
Thread.sleep(10_000)
}On the JVM, use the runInterruptible function to propagate cancellations to blocking JVM code as thread interruptions.
See the Make coroutines react to cancellation section of the coroutines guide for details.
TimeoutCancellationException is not considered an error
Consider this code:
coroutineScope {
launch {
withTimeout(10.milliseconds) {
// Some operation that is going to time out
awaitCancellation()
}
}
}Here, the timeout will be triggered, and withTimeout will finish with a TimeoutCancellationException. However, coroutineScope will finish normally. The reason is that when coroutines finish with a CancellationException, the error does not get propagated to the parent, just like it doesn't when a child actually gets cancelled.
For ensuring that timeouts are treated as true errors that should cause the parent to fail, use withTimeoutOrNull and check the return value:
coroutineScope {
launch {
withTimeoutOrNull(10.milliseconds) {
// Some operation that is going to time out
awaitCancellation()
} ?: error("Timed out!")
}
}If withTimeout has to return a nullable value, and so withTimeoutOrNull cannot be used, this pattern can help instead:
coroutineScope {
launch {
try {
withTimeout(10.milliseconds) {
// Some operation that is going to time out
awaitCancellation()
}
} catch (e: TimeoutCancellationException) {
error("Timed out!")
}
}
}Another option is to specify the timeout action in a select invocation with an onTimeout clause.
Returning closeable resources
Values returned from withTimeout will typically be lost if the caller is cancelled.
See the corresponding section in the coroutineScope documentation for details.