I have some (blocking / non-coroutine) code unter ...
# kotest
s
I have some (blocking / non-coroutine) code unter test that erroneously runs into and endless recursion. Is it expected that
wuthTimeout
is not able to break out of this?
I guess that's because of the problem described here. Unfortunately, I cannot make the code under test cancellable.
BTW, using
blockingTest = true
as described here also didn't work.
o
As you found out, cancelling a coroutine requires cooperation. What Kotest does on the JVM with
blockingTest
is, it is interrupting and shutting down an entire thread. You cannot use
withTimeout
in this scenario, but you must use Kotest's
timeout
parameter for the test in question. Did you try that?
k
I can reproduce it using Kotest timeout:
Copy code
class MyTest : FreeSpec({
    "test".config(blockingTest = true, timeout = 1.seconds) {
        while (true) {}  // Does not time out!
    }
}
s
Did you try that?
Yes, I did. As @Klitos Kyriacou points out, it does not work.
o
That's a Java limitation: Unlike CPU/OS-level interrupts, Java interrupts are not preemptive. CPU-bound code continues to execute, because
Thread.interrupt
just sets an "interrupt status" flag. This flag is checked at specific execution points, see the docs and this Stack Overflow answer.
s
Ouch. I guess that should be documented at https://kotest.io/docs/framework/timeouts/blocking-tests.html.
So is there any solution for my case?
o
Not really, unless you touch your blocking code. On the OS level, the only option you'd have is killing the entire JVM, which is probably not what you'd like to do.
🙁 1
k
It used to be possible in Java to forcibly kill a running thread, but that ability has recently been removed. Compare: https://docs.oracle.com/en/java/javase/19/docs/api/java.base/java/lang/Thread.html#stop() https://docs.oracle.com/en/java/javase/20/docs/api/java.base/java/lang/Thread.html#stop()
😯 1
s
Thanks for you help guys, quite informative!
o
Noticeable remark in the docs on Java Thread Primitive Deprecation – What if a thread doesn't respond to
Thread.interrupt
?:
Unfortunately, there really isn't any technique that works in general. It should be noted that in all situations where a waiting thread doesn't respond to
Thread.interrupt
, it wouldn't respond to
Thread.stop
either.
So basically there is no practical and safe way of preemptive termination in today's modern concurrent architectures. Preemptive termination could always affect other parts of concurrently running code, making it inherently unsafe and almost impossible to get right. So we should all aim for cooperative cancellation and instrument CPU-bound code with interception points, where we could respond to cancellation requests and/or do some health checks to avoid logic errors leading to non-terminating execution or other forms of excessive resource consumption.
💯 1