Reputation: 9103
I need my code to run a block and return value after 1 second in case timeout but let it finish the job.
I managed to implement something that works but IDE suggest replacing async
with withContext(DefaultDispatcher)
but it's not working the same.
So my question is how to make it work without IDE warnings. I am new to Kotlin Coroutines so I might be missing something here.
@Test
fun how_timeout_with_null_works() = runBlocking<Unit> {
val time = measureTimeMillis {
println("Start test")
val result = withTimeoutOrNull(1, TimeUnit.SECONDS) {
async { doSomeHardWork() }.await()
}
println("End test $result")
}
println("Time $time")
delay(3000)
}
private suspend fun doSomeHardWork(): String {
println("start hard work")
Thread.sleep(2000)
print("end hard work")
return "[hard work done]"
}
Upvotes: 3
Views: 4556
Reputation: 28698
IDE gives a warning in this case because async(ctx) { ... }.await()
is usually a mistake and withContext(ctx) { ... }
usually better reflects the original intent of the author of the code.
In case of your code, your intent is different. Your intent is to await for 1 second, without constraining your doSomeHardWork
code. However, the structure of your code does not reflect your intent. You've wrapped the whole block into withTimeout
and put doSomeHardWork
inside of it, while your intent was only to do a time-limited wait for it. So, if you rewrite your code in the way where the structure of your code matches your intent, it will work without any warnings:
val work = async { doSomeHardWork() } // start work
val result = withTimeoutOrNull(1, TimeUnit.SECONDS) { work.await() } // wait with timeout
If you happen to need this pattern of code more than once, then you can define yourself a handy extension:
suspend fun <T> Deferred<T>.awaitWithTimeout(time: Long, unit: TimeUnit): T? =
withTimeoutOrNull(time, unit) { await() }
And then write even nicer code that reflects your intent:
val result = async { doSomeHardWork() }.awaitWithTimeout(1, TimeUnit.SECONDS)
Be careful, though. These coroutines that you start with async
will continue running after the wait had timed out. This can easily lead to resource leaks, unless you take steps to limit the number of those concurrently running background jobs.
Upvotes: 7