Given we have a CompletableFuture f
, in kotlin suspendable scope we can call f.await()
and we will suspend until its done.
I'm having trouble implementing a similar function with signature f.await(t)
which must suspend for maximum t
milliseconds or return sooner if future did complete within that duration (whichever happens first).
Here is what i tried.
/**
* Suspend current method until future is done or specified duration expires,
* whichever happens first without cancelling the future.
* Returns true if its done, false otherwise.
*/
suspend fun <T> ListenableFuture<T>.await(duration: Long): Boolean {
val future = this
try {
withTimeout(duration) {
withContext(NonCancellable) { // this does not help either
future.await() // i do not expect the future itself to be cancelled
}
}
} catch (t: TimeoutCancellationException) {
// we expected this
} catch (e: Throwable) {
e.printStackTrace()
}
return future.isDone
}
fun main(args: Array<String>) = runBlocking<Unit> {
val future = GlobalScope.future {
try {
repeat(5) {
println("computing")
delay(500)
}
println("complete")
} finally {
withContext(NonCancellable) {
println("cancelling")
delay(500)
println("cancelled")
}
}
}
for (i in 0..10) {
if (future.await(2000)) {
println("checking : done")
} else {
println("checking : not done")
}
}
}
I also need a similar function for a job. But maybe solution for this will also help me with that...
Output for this is
computing
computing
computing
computing
checking : done
checking : done
checking : done
checking : done
cancelling
checking : done
checking : done
checking : done
checking : done
checking : done
checking : done
checking : done
Here is what i came up with, i believe this is not a good solution since, i'm most likely creating a lot of garbage for rather primitive task.
this will give output of
which is what we wanted...
I've written some test code:
After we run this code we will get an output:
We see that our extension function
await
returnsnull
because we set timeout to 2000 milliseconds butCompletableFuture
completes after 3000 milliseconds. In this caseCompletableFuture
is cancelled(itsisCancelled
property returnstrue
), but the Thread which we ran incalculateAsync
function continues executing (we see it in the logsafter sleep
).If we set timeout duration to 4000 milliseconds
future.await(4000)
in themain
function, we will see next output:Now we have some result because
CompletableFuture
is executed faster than 4000 millisecond.