Timeouts in Kotlin

Timeouts are important for programs that connect to external resources or that otherwise need to bound execution time. Implementing timeouts in Kotlin is straightforward using coroutines and withTimeout function.

import kotlinx.coroutines.*
import kotlin.time.Duration.Companion.seconds

suspend fun main() = runBlocking {
    // For our example, suppose we're executing an external
    // call that returns its result after 2s. We'll use a
    // suspending function to simulate this delay.
    suspend fun fetchResult1(): String {
        delay(2.seconds)
        return "result 1"
    }

    // Here we use `withTimeout` to implement a timeout.
    // If the operation takes more than the allowed 1s,
    // it will throw a TimeoutCancellationException.
    try {
        val result = withTimeout(1.seconds) {
            fetchResult1()
        }
        println(result)
    } catch (e: TimeoutCancellationException) {
        println("timeout 1")
    }

    // If we allow a longer timeout of 3s, then the call
    // will succeed and we'll print the result.
    suspend fun fetchResult2(): String {
        delay(2.seconds)
        return "result 2"
    }

    try {
        val result = withTimeout(3.seconds) {
            fetchResult2()
        }
        println(result)
    } catch (e: TimeoutCancellationException) {
        println("timeout 2")
    }
}

Running this program shows the first operation timing out and the second succeeding.

$ kotlinc -cp kotlinx-coroutines-core.jar timeouts.kt -include-runtime -d timeouts.jar
$ java -jar timeouts.jar
timeout 1
result 2

In this Kotlin version:

  1. We use Kotlin Coroutines to handle asynchronous operations. The runBlocking function is used to bridge between the regular and coroutine world.

  2. Instead of channels and goroutines, we use suspending functions to simulate our delayed operations.

  3. The select statement is replaced with the withTimeout function, which automatically throws a TimeoutCancellationException if the operation doesn’t complete within the specified time.

  4. We use try-catch blocks to handle the timeout exceptions, printing either the result or the timeout message.

  5. The time.Sleep calls are replaced with delay function calls, which are more idiomatic in Kotlin coroutines.

This approach provides a clean and straightforward way to implement timeouts in Kotlin, leveraging the power of coroutines.