Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Kotlin Coroutines with timeout

I'm currently writing a test-function which should run a block or (when a certain timeout is reached) throws an exception.

I was trying this with Coroutines in Kotlin but ended up with a mixture of Coroutines and CompletableFuture:

fun <T> runBlockWithTimeout(maxTimeout: Long, block: () -> T ): T {
    val future = CompletableFuture<T>()

    // runs the coroutine
    launch { block() }

    return future.get(maxTimeout, TimeUnit.MILLISECONDS)
}

This works, but I'm not sure if this is the intended way to solve that problem in kotlin.

I also tried other approaches:

runBlocking {
    withTimeout(maxTimeout) {
        block()
    }
}

But this seems not to work as soon as the block calls e.g. Thread.sleep(...)

So is the CompletableFuture approach the way to go or is there a better one?

update 1 What I want to achieve:

Async Integration-Test code (like receiving data from RabbitMq) should be tested somehow like this:

var rabbitResults: List = ... // are filled async via RabbitListeners
...
waitMax(1000).toSucceed {
    assertThat(rabbitResults).hasSize(1)
}
waitMax(1000).toSucceed {
    assertThat(nextQueue).hasSize(3)
}
...
like image 531
guenhter Avatar asked Dec 04 '17 14:12

guenhter


People also ask

How do you stop coroutines Kotlin?

For instance, in Android, we cancel all the coroutines started in a view when a user leaves this view. class ProfileViewModel : ViewModel() { private val scope = CoroutineScope(Dispatchers. Main + SupervisorJob()) fun onCreate() { scope. launch { loadUserData() } } override fun onCleared() { scope.

How do you wait for coroutine to finish Kotlin?

When we launch a coroutine in Kotlin using launch we are returned the resulting Job . We can wait for the coroutine to finish by calling join() on the Job.

Do coroutines run concurrently?

Coroutines are a design pattern for writing asynchronous programs for running multiple tasks concurrently. In asynchronous programs, multiple tasks execute in parallel on separate threads without waiting for the other tasks to complete.

When should you not use coroutines?

Answer: a. You should not use them for any foreground task.


1 Answers

withTimeout { ... } is designed to cancel the ongoing operation on timeout, which is only possible if the operation in question is cancellable.

The reason it works with future.get(timeout, unit) is because it only waits with timeout. It does not actually cancel or abort in any way your background operation which still continues to execute after timeout had elapsed.

If you want to mimick similar behavior with coroutines, then you should wait with timeout, like this:

val d = async { block() } // run the block code in background
withTimeout(timeout, unit) { d.await() } // wait with timeout

It works properly because await is a cancellable function which you can verify by reading its API documentation.

However, if you want to actually cancel the ongoing operation on timeout, then then you should implement your code in asyncronous and cancellable way. Cancellation is cooperative, so, to start, the underlying library that you are using in your code has to provide asynchronous API that supports cancellation of ongoing operation.

You can read more about cancellation and timeouts in the corresponding section of the coroutines guide and watch the KotlinConf's Deep Dive into Coroutines on how to integrate coroutines with asynchronous libraries.

like image 58
Roman Elizarov Avatar answered Oct 11 '22 11:10

Roman Elizarov