delay() effective duration interferences from non parent scopes (unpredictable behaviour?) - kotlin

Good morning,
I discovered that delay inside a library that make use of coroutines takes way more than the passed value ( which is 5000ms but often takes up to 20 seconds) I initially supposed some library internal issue which was causing continuation to not be called on time.. but I was unable to find that "issue", changed the scope Dispatchers to unconfined in the library changed nothing, ant the cpu usage is very low on all cores ( 5% ) ,
So I've done some tests using the coroutineContext that library ..
The library context is : BLACKBOX_ACTOR.coroutineContext
val threadPool = Executors.newFixedThreadPool(10)
fun busyCoreDelay(ms:Int){ // CONF WORKS ALWAYS
val tstart=System.currentTimeMillis()
while(System.currentTimeMillis()-tstart<ms){
//noop
}
}
withContext( CoroutineName("Test") + Job() +Dispatchers.Unconfined){
GlobalScope.launch(BLACKBOX_ACTOR.coroutineContext+ Job() + Dispatchers.IO+CoroutineName("Test2") ){ // AA with this DOESNTWORKS
//GlobalScope.launch(CoroutineName("Test3") + Job() +Dispatchers.Unconfined){ // AB with this WORKS (only if AA is not present!)
GlobalScope.launch(CoroutineName("Test3") + Job() +threadPool.asCoroutineDispatcher()){ // AC (works with AB , doesn't with AA )
while(isActive){
val tstart=System.currentTimeMillis()
//delay(5000) // PROBLEM1
busyCoreDelay(5000)
val tend=System.currentTimeMillis()
val delaydelta=tend-tstart
log.warn { "inner delaydelta = ${delaydelta}" }
}
}
}
//
}
the main question is why delay takes more than nominal value even when parent is in unconfined Dispatchers ( this is inside the library, the code is complicated to being posted here, but unconfined dispatcher shouldn't avoid delay() calls to take too much (given cpu almost at 0 ? )
but also... why if I call "delay(5000) // PROBLEM1" with AA + AB or AA+AC doesn't works, and with // AB or AB+AC instead works ?
as my understanding the inner job should escape any parent coroutineContext and dispatcher from BLACKBOX_ACTOR
( the busyCoreDelay always works with all configurations )
thank you very much

Gotcha !
The problem was the usage of Dispatchers.Unconfined from an (mine) internal library
this was causing code to be executed on kotlinx.coroutines.DefaultExecutor ,
once any code run on kotlinx.coroutines.DefaultExecutor delay become "unstable"
( it obviously fail to schedule on time given that continuation point is not reached while other code is being executed )
this triggered buggy behaviour in other libraries which timed out upstream calls and so on..
now, I'm gonna mark the question as answered because the problem was actually my mistake in not noticing the use of Dispatchers.Unconfined but It may also be helpful to others
( enable the maximum loglevel and look in the program log for code that is executed on kotlinx.coroutines.DefaultExecutor )
I hope it will also be useful to others who run into the same type of problem,
I want also to thank all the commenters on the original question.

Related

How to increase Kotlin coroutines when running a test?

I've implemented an integration test. It run some stuff, including two suspend functions which are run inside a launch{}. Now for some reason, when I run more than four of my integration tests, I have six, the fifth job gets cancelled and the IT fails.
This is an excerpt of the code I'm testing:
io.launch {
temporaryStorage.storeFiles(businessProcess)
.publishEvent(businessProcess, expectedDocumentType)
.tapLeft { orchestrationFailure -> orchestrationFailure.handleFailure() }
}
Now the test is actually testing an endpoint. When the endpoint is called, the code I'm testing is called. The specific part which fails, is the part that verifies if a function call in the .publishEvent(...) method is called:
verify(exactly = 1) { eventPublisherMock.publish(any()) }
In the logs I see the first couple of tests run smoothly, but before it runs the test or instance from above it see the job got cancelled: JobImpl{Cancelled}#23edf317 and that the job is not active.
I have a producer function to produce my CoroutineDispatcher. When I up the .maxAsync() and .maxQueue() to respectively 6 and 8 for example it still cancels for some reason. This is the producer:
#Produces
#Singleton
#Named("IO")
fun ioDispatcher(coroutinesDispatcherConfig: CoroutinesDispatcherConfig): CoroutineDispatcher =
SmallRyeManagedExecutor.builder()
.withNewExecutorService()
.maxAsync(coroutinesDispatcherConfig.ioMaxAsync())
.maxQueued(coroutinesDispatcherConfig.ioMaxWaiting())
.build()
.asCoroutineDispatcher()
Does anyone know how I should handle this?

Kotlin Coroutines run synchronously in spite of launch method call

I have a list of employees and I want to hit the API for each of them. In synchronous mode it takes a lot of time and I want to improve the performance with the coroutines. This is what I've done so far:
fun perform() = runBlocking {
employeesSource.getEmployees()
.map { launch { populateWithLeaveBalanceReports(it) } }
.joinAll()
}
suspend fun populateWithLeaveBalanceReports(employee: EmployeeModel) {
println("Start ${COUTNER}")
val receivedReports = reportsSource.getReports(employee.employeeId) // call to a very slow API
receivedReports { employee.addLeaveBalanceReport(it) }
println("Finish ${COUTNER++}")
}
When I try to run this, the code is being run synchronously and in the console I see the following output:
Start 0
Finish 0
Start 1
Finish 1
Start 2
Finish 2
which means that the calls are being done sequentially. If I replace this whole code in the populateWithLeaveBalanceReports function with delay(1000), it will work asynchronously:
Start 0
Start 0
Start 0
Finish 0
Finish 1
Finish 2
What am I doing wrong? Any ideas??
Coroutines don't magically turn your blocking network API into non-blocking. Use launch(Dispatchers.IO) { ... } to run blocking tasks in an elastic thread pool. Just note that this doesn't do much more than the plain-old executorService.submit(blockingTask). It's a bit more convenient because it uses a pre-constructed global thread pool.
These lines might be using a blocking code - the code that relies on blocking threads to wait for task completion.
val receivedReports = reportsSource.getReports(employee.employeeId)
receivedReports { employee.addLeaveBalanceReport(it) }
It is likely that you are using non asynchronous http client or jdbc driver under the hood of reportsSource.getReports call .
If so, you should either
rewrite the code of reportsSource.getReports so it would not rely on any blocking code. This is the new / non-blocking / challenging way
use a threadPool executor to distribute executions manually instead of using coroutines. This is the old / simple way.

Sleep in Spock's Mock waits when run by CompletableFuture

When I separately run the runAsyncWithMock test, it waits for 3 seconds until the mock's execution is finalised, rather than get terminated like the other 2 tests.
I was not able to figure out why.
It is interesting that:
When multiple Runnables are executed by CompletableFuture.runAsync in a row in the runAsyncWithMock test, only the first one waits, the others not.
When having multiple duplicated runAsyncWithMock tests, each and every of them runs for 3s when the whole specification is executed.
When using Class instance rather than a Mock, the test is finalised immediately.
Any idea what I got wrong?
My configuration:
macOS Mojave 10.14.6
Spock 1.3-groovy-2.4
Groovy 2.4.15
JDK 1.8.0_201
The repo containing the whole Gradle project for reproduction:
https://github.com/lobodpav/CompletableFutureMisbehavingTestInSpock
The problematic test's code:
#Stepwise
class SpockCompletableFutureTest extends Specification {
def runnable = Stub(Runnable) {
run() >> {
println "${Date.newInstance()} BEGIN1 in thread ${Thread.currentThread()}"
sleep(3000)
println "${Date.newInstance()} END1 in thread ${Thread.currentThread()}"
}
}
def "runAsyncWithMock"() {
when:
CompletableFuture.runAsync(runnable)
then:
true
}
def "runAsyncWithMockAndClosure"() {
when:
CompletableFuture.runAsync({ runnable.run() })
then:
true
}
def "runAsyncWithClass"() {
when:
CompletableFuture.runAsync(new Runnable() {
void run() {
println "${Date.newInstance()} BEGIN2 in thread ${Thread.currentThread()}"
sleep(3000)
println "${Date.newInstance()} END2 in thread ${Thread.currentThread()}"
}
})
then:
true
}
}
This is caused by the synchronized methods in https://github.com/spockframework/spock/blob/master/spock-core/src/main/java/org/spockframework/mock/runtime/MockController.java when a mock is executed it delegates through the handle method. The Specification also uses the synchronized methods, in this case probably leaveScope, and is thus blocked by the sleeping Stub method.
Since this is a thread interleaving problem I guess that additional closure in runAsyncWithMockAndClosure moves the execution of the stub method behind the leaveScope and thus changes the ordering/blocking.
Oh, just now after writing my last comment I saw a difference:
You use #Stepwise (I didn't when I tried at first), an annotation I almost never use because it creates dependencies between feature methods (bad, bad testing practice). While I cannot say why this has the effect described by you only when running the first method, I can tell you that removing the annotation fixes it.
P.S.: With #Stepwise you cannot even execute the second or third method separately because the runner will always run the preceding one(s) first, because - well, the specification is said to be executed step-wise. ;-)
Update: I could briefly reproduce the problem with #Stepwise, but after recompilation now it does not happen anymore, neither with or without that annotation.

How to make coroutines run in sequence from outside call

I'm a really newbie in coroutines and how it works, I've read a lot about it but I can't seem to understand how or if I can achieve my final goal.
I will try to explain with much detail as I can. Anyway here is my goal:
Ensure that coroutines run sequentially when a method that has said coroutine is called.
I've created a test that matches what I would like to happen:
class TestCoroutines {
#Test
fun test() {
println("Starting...")
runSequentially("A")
runSequentially("B")
Thread.sleep(1000)
}
fun runSequentially(testCase: String) {
GlobalScope.launch {
println("Running test $testCase")
println("Test $testCase ended")
}
}
}
Important Note: I have no control about how many times someone will call runSequentially function. But I want to guarantee that it will be called in order.
This test runs the following outputs:
Starting...
Running test B
Running test A
Test A ended
Test B ended
Starting...
Running test A
Running test B
Test B ended
Test A ended
This is the output I want to achieve :
Starting...
Running test A
Test A ended
Running test B
Test B ended
I think I understand why this is happening: Every time I call runSequentially I'm creating a new Job which is where it's running, and that runs asynchronously.
Is it possible, with coroutines, to guarantee that they will only run after the previous (if it's running) finishes, when we have no control on how many times said coroutine is called?
What you're looking for is a combination of a queue that orders the requests and a worker that serves them. In short, you need an actor:
private val testCaseChannel = GlobalScope.actor<String>(
capacity = Channel.UNLIMITED
) {
for (testCase in channel) {
println("Running test $testCase")
println("Test $testCase ended")
}
}
fun runSequentially(testCase: String) = testCaseChannel.sendBlocking(testCase)

How to propagate exceptions from a Job?

From What is the difference between launch/join and async/await in Kotlin coroutines:
launch is used to fire and forget coroutine. It is like starting a new thread. If the code inside the launch terminates with exception, then it is treated like uncaught exception in a thread -- usually printed to stderr in backend JVM applications and crashes Android applications. join is used to wait for completion of the launched coroutine and it does not propagate its exception. However, a crashed child coroutine cancels its parent with the corresponding exception, too.
If join doesn't propagate the exception, is there a way to wait for completion of a Job which does?
E.g. suppose that some library method returns a Job because it assumed its users wouldn't want to propagate exceptions, but it turns out there is a user who does want it; can this user get it without modifying the library?
Please use join + invokeOnCompletion method
Code will be like this:
suspend fun awaitError(job: Job): Throwable? {
val errorAwaiter = CompletableDeferred<Throwable?>();
job.invokeOnCompletion { errorAwaiter.complete(it) }
require(job.IsActive) {
"Job was completed for too fast, probably error is missed"
}
val errorRaised = errorAwaiter.await();
return when(errorRaised) {
is CancellationException -> null
else -> errorRaised
}
}
Please note, that code will raise error for the fast jobs, so please be carefully. Possible it is better just to return null in this case (in my example).