ksoup icon indicating copy to clipboard operation
ksoup copied to clipboard

Program stalls for over a minute when running `Ksoup.parseGetRequest` or `Ksoup.parseGetRequestBlocking`.

Open jlengrand opened this issue 7 months ago • 20 comments

Describe the bug

Program never terminates when running Ksoup.parseGetRequest or Ksoup.parseGetRequestBlocking.

To Reproduce

The main.kt looks like this :

fun main() {
    runBlocking {
        val doc = Ksoup.parseGetRequest(url = "https://github.com/jlengrand")
        println("title: ${doc.title()}")
    }
}

or

fun main() {
        val doc = Ksoup.parseGetRequestBlocking(url = "https://github.com/jlengrand")
        println("title: ${doc.title()}")
}

and build.gradle.kts

dependencies {
    implementation("com.fleeksoft.ksoup:ksoup:$ksoupVersion")
    implementation("com.fleeksoft.ksoup:ksoup-kotlinx:$ksoupVersion")
    implementation("com.fleeksoft.ksoup:ksoup-network:$ksoupVersion")

    testImplementation(kotlin("test"))
}

Used version : 0.2.3

When running in IntelliJ, using the JDK 23, the title is printed as expected, but the program never exists. When debugging, it seems stuck in a forever loop in the Java Net library :

Image

Expected behavior

The program fetches the html, prints the title, and then exits.

Sample Code If applicable, add sample code or snippets to help explain your problem.

Device (please complete the following information):

  • Device: MBP
  • OS: 15.3.2 (24D81)
  • IntelliJ IDEA 2025.1 (Ultimate Edition)
  • Version 0.2.3
  • JDK 23 Liberica

Additional context Add any other context about the problem here.

jlengrand avatar May 01 '25 07:05 jlengrand

I can reproduce the same on all 0.2.x versions I tried.

jlengrand avatar May 01 '25 07:05 jlengrand

Maybe also worth mentioning that when trying with the -ktor2 version of the dependency, I crashdump consistently when trying to debug :s :

/Users/julienlengrand-lambert/.sdkman/candidates/java/23.0.2.fx-librca/bin/java -agentlib:jdwp=transport=dt_socket,address=127.0.0.1:55044,suspend=y,server=n -javaagent:/Users/julienlengrand-lambert/Library/Caches/JetBrains/IntelliJIdea2025.1/captureAgent/debugger-agent.jar=file:///var/folders/4b/jjn7wslx5fl1r5npk147_9b80000gn/T/capture7697505133932501157.props -agentpath:/private/var/folders/4b/jjn7wslx5fl1r5npk147_9b80000gn/T/idea_libasyncProfiler_dylib_temp_folder/libasyncProfiler.dylib=version,jfr,event=wall,interval=10ms,cstack=no,file=/Users/julienlengrand-lambert/IdeaSnapshots/MainKt_2025_05_01_100016.jfr,log=/private/var/folders/4b/jjn7wslx5fl1r5npk147_9b80000gn/T/MainKt_2025_05_01_100016.jfr.log.txt,logLevel=DEBUG -javaagent:/Users/julienlengrand-lambert/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlinx/kotlinx-coroutines-core-jvm/1.7.1/63a0779cf668e2a47d13fda7c3b0c4f8dc7762f4/kotlinx-coroutines-core-jvm-1.7.1.jar -Dkotlinx.coroutines.debug.enable.creation.stack.trace=false -Ddebugger.agent.enable.coroutines=true -Dkotlinx.coroutines.debug.enable.flows.stack.trace=true -Dkotlinx.coroutines.debug.enable.mutable.state.flows.stack.trace=true -Dfile.encoding=UTF-8 -Dsun.stdout.encoding=UTF-8 -Dsun.stderr.encoding=UTF-8 -classpath /Users/julienlengrand-lambert/Developer/OpenGraphKt/build/classes/kotlin/main:/Users/julienlengrand-lambert/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib/2.1.20/aa8ca79cd50578314f6d1180c47cbe14c0fee567/kotlin-stdlib-2.1.20.jar:/Users/julienlengrand-lambert/.gradle/caches/modules-2/files-2.1/com.fleeksoft.ksoup/ksoup-network-ktor2-jvm/0.2.3/a8ca6572738dbbc26118000a1dda8769050233b/ksoup-network-ktor2-jvm-0.2.3.jar:/Users/julienlengrand-lambert/.gradle/caches/modules-2/files-2.1/com.fleeksoft.ksoup/ksoup-kotlinx-jvm/0.2.3/711c10d79084f9cbacf70a5ec272ad7b24cdd4ed/ksoup-kotlinx-jvm-0.2.3.jar:/Users/julienlengrand-lambert/.gradle/caches/modules-2/files-2.1/com.fleeksoft.ksoup/ksoup-jvm/0.2.3/16edb3132c6f9502da84aabf289c93c5abd073c9/ksoup-jvm-0.2.3.jar:/Users/julienlengrand-lambert/.gradle/caches/modules-2/files-2.1/org.jetbrains/annotations/23.0.0/8cc20c07506ec18e0834947b84a864bfc094484e/annotations-23.0.0.jar:/Users/julienlengrand-lambert/.gradle/caches/modules-2/files-2.1/io.ktor/ktor-client-core-jvm/2.3.13/67cbe7757ed4a0818dadac88c0aad42c7c0a665d/ktor-client-core-jvm-2.3.13.jar:/Users/julienlengrand-lambert/.gradle/caches/modules-2/files-2.1/com.fleeksoft.ksoup/ksoup-io-jvm/0.2.3/87db6425a824906e207ee3257c13c86ed1cc3bae/ksoup-io-jvm-0.2.3.jar:/Users/julienlengrand-lambert/.gradle/caches/modules-2/files-2.1/com.fleeksoft.io/kotlinx-io-jvm/0.0.4/c45eb73d1e182782650eb462ee1df1ae9dd93a06/kotlinx-io-jvm-0.0.4.jar:/Users/julienlengrand-lambert/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlinx/kotlinx-io-core-jvm/0.7.0/1d9595ed390f6304ce90a049e6b2f1fab3b408c4/kotlinx-io-core-jvm-0.7.0.jar:/Users/julienlengrand-lambert/.gradle/caches/modules-2/files-2.1/com.fleeksoft.charset/charset-jvm/0.0.4/b39ec1572ccf489ebd0b0e3d3318fd227ade352/charset-jvm-0.0.4.jar:/Users/julienlengrand-lambert/.gradle/caches/modules-2/files-2.1/com.fleeksoft.io/io-core-jvm/0.0.4/5ace56b2095fa4faabc092bcc08077e2d8c8edc9/io-core-jvm-0.0.4.jar:/Users/julienlengrand-lambert/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib-jdk8/1.8.22/b25c86d47d6b962b9cf0f8c3f320c8a10eea3dd1/kotlin-stdlib-jdk8-1.8.22.jar:/Users/julienlengrand-lambert/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib-jdk7/1.8.22/4dabb8248310d833bb6a8b516024a91fd3d275c/kotlin-stdlib-jdk7-1.8.22.jar:/Users/julienlengrand-lambert/.gradle/caches/modules-2/files-2.1/org.slf4j/slf4j-api/1.7.36/6c62681a2f655b49963a5983b8b0950a6120ae14/slf4j-api-1.7.36.jar:/Users/julienlengrand-lambert/.gradle/caches/modules-2/files-2.1/io.ktor/ktor-events-jvm/2.3.13/f0d36d45767371f12fc7312f28c3ff7aa8bb5cf8/ktor-events-jvm-2.3.13.jar:/Users/julienlengrand-lambert/.gradle/caches/modules-2/files-2.1/io.ktor/ktor-websocket-serialization-jvm/2.3.13/57e6ad17d18e24994a21ee58d683e231a3995200/ktor-websocket-serialization-jvm-2.3.13.jar:/Users/julienlengrand-lambert/.gradle/caches/modules-2/files-2.1/io.ktor/ktor-http-jvm/2.3.13/826d602a0e7ce29437e71f2bbc280824154f4498/ktor-http-jvm-2.3.13.jar:/Users/julienlengrand-lambert/.gradle/caches/modules-2/files-2.1/com.fleeksoft.io/io-jvm/0.0.4/84f67c483b172b5903aa27da230d28bb6ddc20f9/io-jvm-0.0.4.jar:/Users/julienlengrand-lambert/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlinx/kotlinx-io-bytestring-jvm/0.7.0/ffe5bd231da40d21870250703326113277dbf9c3/kotlinx-io-bytestring-jvm-0.7.0.jar:/Users/julienlengrand-lambert/.gradle/caches/modules-2/files-2.1/io.ktor/ktor-utils-jvm/2.3.13/1c46fa7ee1bddb3427f98c6f5c385fd5f8eddbc6/ktor-utils-jvm-2.3.13.jar:/Users/julienlengrand-lambert/.gradle/caches/modules-2/files-2.1/io.ktor/ktor-serialization-jvm/2.3.13/294e7597d203948a673ba6e4df80ba3417533326/ktor-serialization-jvm-2.3.13.jar:/Users/julienlengrand-lambert/.gradle/caches/modules-2/files-2.1/io.ktor/ktor-io-jvm/2.3.13/c72b740fc87089f7389799f9a86fb5cc0ad83797/ktor-io-jvm-2.3.13.jar:/Users/julienlengrand-lambert/.gradle/caches/modules-2/files-2.1/io.ktor/ktor-websockets-jvm/2.3.13/316c829551c015c4bb31c63a52e742341a51d576/ktor-websockets-jvm-2.3.13.jar:/Users/julienlengrand-lambert/.gradle/caches/modules-2/files-2.1/io.ktor/ktor-client-okhttp-jvm/2.3.13/d662d879f5938a206b4a34ce3cdaf5f9f0f6d05e/ktor-client-okhttp-jvm-2.3.13.jar:/Users/julienlengrand-lambert/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlinx/kotlinx-coroutines-core-jvm/1.10.2/4a9f78ef49483748e2c129f3d124b8fa249dafbf/kotlinx-coroutines-core-jvm-1.10.2.jar:/Users/julienlengrand-lambert/.gradle/caches/modules-2/files-2.1/co.touchlab/stately-concurrency-jvm/2.1.0/6285428408c4d7e4a6d9a09511de877103effd81/stately-concurrency-jvm-2.1.0.jar:/Users/julienlengrand-lambert/.gradle/caches/modules-2/files-2.1/com.squareup.okhttp3/okhttp/4.12.0/2f4525d4a200e97e1b87449c2cd9bd2e25b7e8cd/okhttp-4.12.0.jar:/Users/julienlengrand-lambert/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlinx/kotlinx-coroutines-jdk8/1.10.2/809f71bf722bad7e78ebe8ec710c0327c23b7a31/kotlinx-coroutines-jdk8-1.10.2.jar:/Users/julienlengrand-lambert/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlinx/kotlinx-coroutines-slf4j/1.10.2/1271f9d4a929150bb87ab8d1dc1e86d4bcf039f3/kotlinx-coroutines-slf4j-1.10.2.jar:/Users/julienlengrand-lambert/.gradle/caches/modules-2/files-2.1/com.squareup.okio/okio-jvm/3.7.0/276b999b41f7dcde00054848fc53af338d86b349/okio-jvm-3.7.0.jar:/Users/julienlengrand-lambert/.gradle/caches/modules-2/files-2.1/co.touchlab/stately-strict-jvm/2.1.0/3ae8369209065455f4630793bf6aca0fb88c8b6b/stately-strict-jvm-2.1.0.jar:/Users/julienlengrand-lambert/Applications/IntelliJ IDEA Ultimate.app/Contents/lib/idea_rt.jar nl.lengrand.MainKt
Connected to the target VM, address: '127.0.0.1:55044', transport: 'socket'
Exception in thread "main" java.lang.reflect.InvocationTargetException
	at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:118)
	at java.base/java.lang.reflect.Method.invoke(Method.java:580)
	at java.instrument/sun.instrument.InstrumentationImpl.loadClassAndStartAgent(InstrumentationImpl.java:560)
	at java.instrument/sun.instrument.InstrumentationImpl.loadClassAndCallPremain(InstrumentationImpl.java:572)
Caused by: java.lang.NoSuchMethodError: 'void kotlinx.coroutines.debug.internal.DebugProbesImpl.setEnableCreationStackTraces(boolean)'
	at kotlinx.coroutines.debug.AgentPremain.premain(AgentPremain.kt:33)
	at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
	... 3 more
*** java.lang.instrument ASSERTION FAILED ***: "!errorOutstanding" with message Outstanding error when calling method in invokeJavaAgentMainMethod at src/java.instrument/share/native/libinstrument/JPLISAgent.c line: 627
*** java.lang.instrument ASSERTION FAILED ***: "success" with message invokeJavaAgentMainMethod failed at src/java.instrument/share/native/libinstrument/JPLISAgent.c line: 466
*** java.lang.instrument ASSERTION FAILED ***: "result" with message agent load/premain call failed at src/java.instrument/share/native/libinstrument/JPLISAgent.c line: 429
FATAL ERROR in native method: processing of -javaagent failed, processJavaStart failed
Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code)
V  [libjvm.dylib+0x533f14]  jni_FatalError+0x7c
V  [libjvm.dylib+0x6aac88]  JvmtiExport::post_vm_initialized()+0x2b8
V  [libjvm.dylib+0xa46310]  Threads::create_vm(JavaVMInitArgs*, bool*)+0x818
V  [libjvm.dylib+0x5529fc]  JNI_CreateJavaVM+0x74
C  [libjli.dylib+0xa518]  JavaMain+0x100
C  [libjli.dylib+0xd658]  ThreadJavaMain+0xc
C  [libsystem_pthread.dylib+0x72e4]  _pthread_start+0x88
Disconnected from the target VM, address: '127.0.0.1:55044', transport: 'socket'

Process finished with exit code 134 (interrupted by signal 6:SIGABRT)

This might be related to this : https://youtrack.jetbrains.com/issue/KTIJ-19345

jlengrand avatar May 01 '25 08:05 jlengrand

Also can reproduce the behavior consistently on various JVMs range 21 to 24, Oracle and Temurin.

jlengrand avatar May 01 '25 08:05 jlengrand

Changing the code to

fun main() {
    val doc = Ksoup.parseGetRequestBlocking(url = "https://github.com/jlengrand")
    println("title: ${doc.title()}")
    exitProcess(0)
}

works as intended, but I don't really see why it should be needed.

jlengrand avatar May 01 '25 08:05 jlengrand

Interestingly, debugging it and stepping over seems to lead to the Http2Connection class and get to the finally method, which closes the coroutine. I'm curious why the debugging changes the behaviour

jlengrand avatar May 01 '25 08:05 jlengrand

Hum, same behaviour using okio too. I'm really confused now.

jlengrand avatar May 01 '25 08:05 jlengrand

I can also confirm the same using gradle, so it doesn't seem like an IntelliJ issue :

Image

jlengrand avatar May 01 '25 08:05 jlengrand

oh wait! It looks like it exits after all, simply it takes over a minute for some reason 🤔

Image

jlengrand avatar May 01 '25 08:05 jlengrand

Hi @jlengrand ,Can you please provide the link you’re using? Also, did you try testing it with any other website? The issue might be with the site itself. Try fetching the website using Postman or curl command and see if you’re experiencing the same delay.

itboy87 avatar May 01 '25 18:05 itboy87

Hey, thanks for the answer. So I made a repo to reproduce the behaviour.

From what I can see, the requests themselves are fast (all under a second) but the program itself will stall for about a minute before actually exiting. This is visible both when running locally using gradle, and on GitHub actions directly.

Even when fetching 6 URLs, the run time is over 2 minutes.

Image

Curious if you experience the same, and if you know when that can come from.

jlengrand avatar May 04 '25 09:05 jlengrand

@jlengrand I think there’s a misunderstanding — you’re looking at the Gradle time, which is 2m 23s. That reflects the overall process including the build time, whereas the actual code execution time is only around 2 seconds.

itboy87 avatar May 05 '25 12:05 itboy87

Hey! No, I am not exactly. Build time is around 12 seconds. Execution time is 2:12, the last minute spent idling in the main function. Happy to record my screen if that helps, but i can also reproduce on my IntelliJ. Using gradle here so you can easily reproduce and show the behavior is the same on github servers

jlengrand avatar May 05 '25 12:05 jlengrand

@jlengrand these are the logs from your action, which show that Ksoup.parseGetRequestBlocking

took only 1.15 seconds. title: jlengrand (julien Lengrand-Lambert) · GitHub time: 1.155155728s to fetch GitHub page blocking title: Wikipedia:Getting to Philosophy - Wikipedia time: 139.230200ms to fetch Wikipedia page blocking SLF4J(W): See https://www.slf4j.org/codes.html#noProviders for further details. title: Julien's DevRel corner time: 1.123993290s to fetch blog page blocking //// title: jlengrand (julien Lengrand-Lambert) · GitHub time: 63.923369ms to fetch GitHub page blocking title: Wikipedia:Getting to Philosophy - Wikipedia time: 24.714629ms to fetch Wikipedia page title: Julien's DevRel corner time: 232.756820ms to fetch blog page

itboy87 avatar May 05 '25 12:05 itboy87

I’ve attached the source code and added a unit test — please run it, as it will show you the exact code execution time.

ksoup-test-119.zip

You can check the unit test results from my system — it clearly shows that your code took a total of 4 seconds to run, with 1.5 seconds spent on Ksoup.parseGetRequestBlocking. Image

itboy87 avatar May 05 '25 12:05 itboy87

Again:

  • yes, the requests are fast, i m timing them.
  • but the program stalls for a minute after the requests and doesn't exit straight away like it should.

There is a one minute delay, blocked in the thread waiting loop, at the end of the execution; even if requests themselves are fast.

jlengrand avatar May 05 '25 12:05 jlengrand

I’ve attached the source code and added a unit test — please run it, as it will show you the exact code execution time.

ksoup-test-119.zip

You can check the unit test results from my system — it clearly shows that your code took a total of 4 seconds to run, with 1.5 seconds spent on Ksoup.parseGetRequestBlocking. Image

I ll try that tonight thanks

jlengrand avatar May 05 '25 12:05 jlengrand

@jlengrand Okay, I got it now and I can reproduce the issue. This seems to be related to network requests only for now — I’ll look into it further.

itboy87 avatar May 05 '25 12:05 itboy87

Thanks for listening and taking the time to reproduce 😊

jlengrand avatar May 05 '25 12:05 jlengrand

Thank you for pointing out this issue, It’s related to the Ktor OkHttp client. I’ll check if it’s already been reported; otherwise, I’ll open an issue on the Ktor tracker. I can reproduce it with the Ktor + OkHttp client without Ksoup.

itboy87 avatar May 05 '25 19:05 itboy87

@jlengrand issue opened: KTOR-8466 For now you can remove ksoup-network and use only ksoup, but perform the network request manually and pass the HTML to Ksoup.parse. You can also use ksoup-kotlinx to call httpResponse.asInputStream() and pass the resulting InputStream to Ksoup.parseInput.

itboy87 avatar May 05 '25 20:05 itboy87

@jlengrand fixed in v0.2.4

itboy87 avatar May 28 '25 18:05 itboy87

Thanks, I'll have a look!

jlengrand avatar Jun 02 '25 22:06 jlengrand

Can confirm, TY :)

jlengrand avatar Jun 04 '25 15:06 jlengrand