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)
}
...
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.
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.
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.
Answer: a. You should not use them for any foreground task.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With