Is is possible to suspend a coroutine with a timeout?
You can combine withTimeout
and suspendCancellableCoroutine
in a straightforward way for the desired effect:
suspend inline fun <T> suspendCoroutineWithTimeout(
timeout: Long, unit: TimeUnit,
crossinline block: (Continuation<T>) -> Unit
) = withTimeout(timeout, unit) {
suspendCancellableCoroutine(block = block)
}
Perfect answer from @Roman Elizarov.. Just adding my 2 cents on it because I needed a return from that call.. So adding T? return it would be ...
suspend inline fun <T> suspendCoroutineWithTimeout(timeout: Long, crossinline block: (Continuation<T>) -> Unit ) : T? {
var finalValue : T? = null
withTimeoutOrNull(timeout) {
finalValue = suspendCancellableCoroutine(block = block)
}
return finalValue
}
If you're using suspendCoroutine
, that means you have full control over what you do with the continuation you got. For example, you can pass it to the callback-based async API and, additionally, to a scheduled task that will resume it with exception:
suspend fun mySuspendFun(timeout: Long): String {
val didResume = AtomicBoolean()
fun markResumed() = !didResume.getAndSet(true)
return suspendCoroutine { cont ->
launch(CommonPool) {
delay(timeout)
if (markResumed()) {
cont.resumeWithException(TimeoutException())
}
}
// call Async API, and in the callback, use
// if (markResumed()) {
// cont.resume(result)
// }
}
}
However, Kotlin's standard library supports your use case first-class, as described in Roman Elizarov's answer. I suggest you use that approach in your project.