square / okhttp

Square’s meticulous HTTP client for the JVM, Android, and GraalVM.

Home Page:https://square.github.io/okhttp/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Add proper shutdown support for your library

balayanv opened this issue · comments

In my company we test software carefully to not let any resources leak, so after each test we check if there are any threads that are still alive.

Okhttp does not provide any reasonable way to shut it down peroperly.
after evicting connection pool and shutting down the executor used in dispatcher i still have all these threads hanging out in my jvm... not only they do not want to die with interrupt() but they are not daemon threads (so my jvm cant evn shut down unless my http library deems its ok to do so)...

Here is the list of threads that stay alive.

Thread still running Thread[OkHttp ConnectionPool,5,main]
	at java.lang.Object.wait(Native Method)
	at java.lang.Object.wait(Object.java:460)
	at okhttp3.internal.connection.RealConnectionPool.lambda$new$0(RealConnectionPool.java:62)
	at okhttp3.internal.connection.RealConnectionPool$$Lambda$250/1746421161.run(Unknown Source)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
Thread still running Thread[Okio Watchdog,5,main]
	at java.lang.Object.wait(Native Method)
	at okio.AsyncTimeout.awaitTimeout(AsyncTimeout.java:348)
	at okio.AsyncTimeout$Watchdog.run(AsyncTimeout.java:313)
Thread still running Thread[OkHttp ConnectionPool,5,main]
	at java.lang.Object.wait(Native Method)
	at java.lang.Object.wait(Object.java:460)
	at okhttp3.internal.connection.RealConnectionPool.lambda$new$0(RealConnectionPool.java:62)
	at okhttp3.internal.connection.RealConnectionPool$$Lambda$250/1746421161.run(Unknown Source)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
Thread still running Thread[Okio Watchdog,5,main]
	at java.lang.Object.wait(Native Method)
	at okio.AsyncTimeout.awaitTimeout(AsyncTimeout.java:348)
	at okio.AsyncTimeout$Watchdog.run(AsyncTimeout.java:313)
Thread still running Thread[OkHttp ConnectionPool,5,main]
	at java.lang.Object.wait(Native Method)
	at java.lang.Object.wait(Object.java:460)
	at okhttp3.internal.connection.RealConnectionPool.lambda$new$0(RealConnectionPool.java:62)
	at okhttp3.internal.connection.RealConnectionPool$$Lambda$250/1746421161.run(Unknown Source)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
Thread still running Thread[Okio Watchdog,5,main]
	at java.lang.Object.wait(Native Method)
	at okio.AsyncTimeout.awaitTimeout(AsyncTimeout.java:348)
	at okio.AsyncTimeout$Watchdog.run(AsyncTimeout.java:313)
Thread still running Thread[OkHttp ConnectionPool,5,main]
	at java.lang.Object.wait(Native Method)
	at java.lang.Object.wait(Object.java:460)
	at okhttp3.internal.connection.RealConnectionPool.lambda$new$0(RealConnectionPool.java:62)
	at okhttp3.internal.connection.RealConnectionPool$$Lambda$250/1746421161.run(Unknown Source)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
Thread still running Thread[Okio Watchdog,5,main]
	at java.lang.Object.wait(Native Method)
	at okio.AsyncTimeout.awaitTimeout(AsyncTimeout.java:348)
	at okio.AsyncTimeout$Watchdog.run(AsyncTimeout.java:313)

I went trough okhttp code, and its amazing to me that you guys are smart enough to do all these clever things with your buffers but you do not want to properly shut things down... i'm sure it would end badly if you had similar approach to handling byte buffers...

Its near impossible to kill these threads unless they cooperate. Its also unacceptable to start non daemon threads from any library... a thread being not daemon should be a choice by application owner, not the library. Most libraries provide means to control the threads and executors, not in your case. Even though i can supply custom Dispatcher, i cannot control how your connection pool roams around creating threads and executor services.

Implement a simple close() on your client, and shut down all your connection pools dispatchers and everything.

Seriously? shutdown isnt necessary?
https://square.github.io/okhttp/4.x/okhttp/okhttp3/-ok-http-client/#shutdown-isnt-necessary

What version of OkHttp are you using? Try upgrading.

unfortunately for performance we did some hacks to use our event loop from within your code
i cant easily migrate it (mostly since its kotlin code that looks like crap from java)

However i'll argue its irrelevant, my case is one from many.

Even in the latest version of ok http i do not see shutdown or close method on the client...
https://github.com/square/okhttp/blob/master/okhttp/src/jvmMain/kotlin/okhttp3/OkHttpClient.kt

Is there some proper shutdown mechanism implemented on latest version?

Yeah, the Kotlin version has lots of fixes, including this. In particular interrupting background threads will cause them to immediately exit.

What don't you like about calling into Kotlin? Extra autocomplete suggestions? Or when you browse our source?

no i love kotlin, and its my main language outside of this project
but yes browsing the source when its in java form... i'm not sure why jetbrains makes you put all those annotation when they could easily generate very readable java from kotlin code