Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to step through suspend function calls when debugging Kotlin coroutines

How is it possible to debug Kotlin code when stepping into or out of a "suspend" function? (see example below).

fun mainFunction() = runBlocking {      println("before suspend call")      anotherFunction()      println("after suspend call") }  suspend fun anotherFunction() {     // do something } 

I understand that Kotlin co-routines do a lot of magic when executing suspend functions and that the execution may switch threads at that moment. So when stepping out of "anotherFunction()" I only get to step through coroutine framework code and can't get back to the "mainFunction()".

However, I wonder if it is possible to debug this as if no co-routines were involved. Is there a tool or a library that enables this feature? Is it maybe on the roadmap for co-routine support?

A feature as simple as a compiler flag disabling co-routine magic would already go a long way, but I wasn't able to find anything.

The only useful thing I did find is: -ea JVM parameter also activates kotlin debug mode which will at least "fix" stack traces for exceptions.

like image 937
Daniel Avatar asked Apr 19 '19 16:04

Daniel


People also ask

How does suspension work in Kotlin coroutines?

Suspending functions are at the center of everything coroutines. A suspending function is simply a function that can be paused and resumed at a later time. They can execute a long running operation and wait for it to complete without blocking.

How does Kotlin handle suspend function?

We just have to use the suspend keyword. Note: Suspend functions are only allowed to be called from a coroutine or another suspend function. You can see that the async function which includes the keyword suspend. So, in order to use that, we need to make our function suspend too.

What is the difference between suspending vs blocking in Kotlin?

BLOCKING: Function A has to be completed before Function B continues. The thread is locked for Function A to complete its execution. SUSPENDING: Function A, while has started, could be suspended, and let Function B execute, then only resume later. The thread is not locked by Function A.


1 Answers

This page shows some general techniques. In short, run with enabled assertions (-ea JVM flag).

kotlinx-coroutines-debug module is specifically designed for what its name says. This is how I use it in unit tests;

runBlocking {     DebugProbes.install()     val deferred = async { methodUnderTest() }     delay(3000)     DebugProbes.dumpCoroutines()     println("\nDumping only deferred")     DebugProbes.printJob(deferred)     DebugProbes.uninstall()     cleanup() } 

There's a JUnit4 rule to reduce the boilerplate, but you shouldn't be using JUnit4 in late 2020.

Also, Kotlin 1.4.0-RC and later has support for debugging Coroutines from inside the IDE, but just like everything new from JetBrains, I found it half-baked and not always showing suspended coroutines; kotlinx-coroutines-debug works better. https://blog.jetbrains.com/kotlin/2020/07/kotlin-1-4-rc-debugging-coroutines/

Edit Oct 2020:

I created a JUnit 5 Extension that can dump coroutines on timeout. https://github.com/asarkar/coroutines-test

like image 193
Abhijit Sarkar Avatar answered Sep 30 '22 23:09

Abhijit Sarkar