-
Notifications
You must be signed in to change notification settings - Fork 1.9k
/
Copy pathTimeouts.kt
81 lines (74 loc) · 2.73 KB
/
Timeouts.kt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
@file:OptIn(ExperimentalContracts::class)
@file:Suppress("LEAKED_IN_PLACE_LAMBDA", "WRONG_INVOCATION_KIND")
package kotlinx.coroutines.timeout
import kotlinx.coroutines.*
import kotlin.contracts.*
import kotlin.coroutines.Continuation
import kotlin.coroutines.intrinsics.suspendCoroutineUninterceptedOrReturn
import kotlin.time.Duration
import kotlin.time.Duration.Companion.milliseconds
/**
* [kotlinx.coroutines.withTimeout] but better
*/
public suspend fun <T> withTimeout(timeMillis: Long, block: suspend CoroutineScope.() -> T): T {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
if (timeMillis <= 0L) throw TimeoutException("Timed out immediately")
return suspendCoroutineUninterceptedOrReturn { uCont ->
setupTimeout(TimeoutCoroutine(timeMillis, uCont), block)
}
}
internal class TimeoutCoroutine<U, in T : U>(
time: Long,
uCont: Continuation<U> // unintercepted continuation
) : TimeoutCoroutineBase<U, T>(time, uCont) {
override fun timeoutException(): Throwable = TimeoutException(time, context.delay, this)
}
/**
* [kotlinx.coroutines.withTimeout] but better
*/
public suspend fun <T> withTimeout(timeout: Duration, block: suspend CoroutineScope.() -> T): T {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
return withTimeout(timeout.toDelayMillis(), block)
}
/**
* This exception is thrown by [withTimeout] to indicate timeout.
*
* Example of usage:
* ```
* suspend fun main() {
* try {
* val result = withTimeout(100.milliseconds) {
* println("Executing long-running operation")
* delay(1.seconds) // Pretending to be slow operation
* 42
* }
* println("Computation result: $result") // Never printed
* } catch (e: TimeoutException) {
* println("Computation failed: ${e.message}")
* }
* }
* ```
*
* ### Implementation note
*
* On the JVM platform, this exception extends `java.util.concurrent.TimeoutException`.
* The main purpose of that is to make `java.util.concurrent.TimeoutException` and `kotlinx.coroutines.TimeoutException`
* interchangeable from the user perspective (i.e. any of them can be caught) and thus less error-prone,
* while allowing the implementation to store auxilary data along with the exception.
*/
public expect class TimeoutException internal constructor(message: String, coroutine: Job?) : Exception {
internal constructor(message: String)
}
private fun TimeoutException(
time: Long,
delay: Delay,
coroutine: Job
): TimeoutException {
val message = (delay as? DelayWithTimeoutDiagnostics)?.timeoutMessage(time.milliseconds)
?: "Timed out waiting for $time ms"
return TimeoutException(message, coroutine)
}