treasure-data / td-client-java

Java Client Library for Treasure Data
http://docs.treasuredata.com/articles/java
Apache License 2.0
12 stars 22 forks source link

fix: Clear interrupted status when okhttp throws InterruptedIOException #245

Closed NicolasRichard closed 1 year ago

NicolasRichard commented 1 year ago

When a thread is interrupted while submitting a request, there's a good chance that the underlying okhttp client will throw an InterruptedIOException.

java.io.InterruptedIOException: interrupted
2023-01-31T23:36:21.823154760Z  at okio.Timeout.throwIfReached(Timeout.java:146)
2023-01-31T23:36:21.823156802Z  at okio.Okio$1.write(Okio.java:76)
2023-01-31T23:36:21.823158760Z  at okio.AsyncTimeout$1.write(AsyncTimeout.java:180)
2023-01-31T23:36:21.823160593Z  at okio.RealBufferedSink.flush(RealBufferedSink.java:224)
2023-01-31T23:36:21.823162385Z  at okhttp3.internal.http2.Http2Writer.flush(Http2Writer.java:121)
2023-01-31T23:36:21.823164302Z  at okhttp3.internal.http2.Http2Connection.flush(Http2Connection.java:439)
2023-01-31T23:36:21.823166302Z  at okhttp3.internal.http2.Http2Stream$FramingSink.close(Http2Stream.java:631)
2023-01-31T23:36:21.823168093Z  at okio.ForwardingSink.close(ForwardingSink.java:47)
2023-01-31T23:36:21.823169885Z  at okhttp3.internal.connection.Exchange$RequestBodySink.close(Exchange.java:253)
2023-01-31T23:36:21.823171885Z  at okio.RealBufferedSink.close(RealBufferedSink.java:248)
2023-01-31T23:36:21.823173802Z  at okhttp3.internal.http.CallServerInterceptor.intercept(CallServerInterceptor.java:70)
2023-01-31T23:36:21.823175760Z  at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:142)
2023-01-31T23:36:21.823177718Z  at okhttp3.internal.connection.ConnectInterceptor.intercept(ConnectInterceptor.java:43)
2023-01-31T23:36:21.823179552Z  at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:142)
2023-01-31T23:36:21.823181302Z  at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:117)
2023-01-31T23:36:21.823183260Z  at okhttp3.internal.cache.CacheInterceptor.intercept(CacheInterceptor.java:94)
2023-01-31T23:36:21.823185218Z  at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:142)
2023-01-31T23:36:21.823187093Z  at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:117)
2023-01-31T23:36:21.823188843Z  at okhttp3.internal.http.BridgeInterceptor.intercept(BridgeInterceptor.java:93)
2023-01-31T23:36:21.823224427Z  at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:142)
2023-01-31T23:36:21.823228010Z  at okhttp3.internal.http.RetryAndFollowUpInterceptor.intercept(RetryAndFollowUpInterceptor.java:88)
2023-01-31T23:36:21.823230010Z  at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:142)
2023-01-31T23:36:21.823231968Z  at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:117)
2023-01-31T23:36:21.823233760Z  at okhttp3.RealCall.getResponseWithInterceptorChain(RealCall.java:229)
2023-01-31T23:36:21.823236760Z  at okhttp3.RealCall.execute(RealCall.java:81)
2023-01-31T23:36:21.823238677Z  at com.treasuredata.client.TDHttpRequestHandler.send(TDHttpRequestHandler.java:55)
2023-01-31T23:36:21.823240468Z  at com.treasuredata.client.TDHttpClient.submitRequest(TDHttpClient.java:405)
2023-01-31T23:36:21.823242385Z  at com.treasuredata.client.TDHttpClient.submitRequest(TDHttpClient.java:475)
2023-01-31T23:36:21.823244302Z  at com.treasuredata.client.TDHttpClient.call(TDHttpClient.java:498)
2023-01-31T23:36:21.823246177Z  at com.treasuredata.client.TDClient.doPost(TDClient.java:290)
2023-01-31T23:36:21.823248093Z  at com.treasuredata.client.TDClient.deleteDatabase(TDClient.java:418)
2023-01-31T23:36:21.823250010Z  at com.treasuredata.client.TDClient.deleteDatabaseIfExists(TDClient.java:426)

Unfortunately, contrary to what you might believe, InterruptedIOException is not a subclass of InterruptedException. Therefore, the exception will bubble up outside of the client. In addition, okhttp client retains the interrupted status when throwing InterruptedIOException, while Thread.sleep clears it.

Therefore, I propose to wrap InterruptedIOException with TDClientInterruptedException. I also suggest to clear the interrupted status to provide a cohesive behavior when a thread is interrupted.