Foso / Ktorfit

HTTP client generator / KSP plugin for Kotlin Multiplatform (Android, iOS, Js, Jvm, Native, WasmJs)) using KSP and Ktor clients inspired by Retrofit https://foso.github.io/Ktorfit
https://foso.github.io/Ktorfit
Apache License 2.0
1.62k stars 43 forks source link

[Bug]: Timeout throws exception outside of scope of SuspendResponseConverter #127

Closed jamesrapadmi closed 1 year ago

jamesrapadmi commented 1 year ago

Ktorfit version

1.0.0-beta16

What happened and how can we reproduce this issue?

I ported from retrofit to ktorfit, and have found that there are a lot of crashes that get through the suspend result converter.

e.g. Timeout

io.ktor.client.plugins.HttpRequestTimeoutException: Request timeout has expired [url=https://www.example.com, request_timeout=30000 ms]
       at io.ktor.client.plugins.HttpTimeout$Plugin$install$1$1$killer$1.invokeSuspend(HttpTimeout.kt:163)
       at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
       at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
       at kotlinx.coroutines.internal.LimitedDispatcher.run(LimitedDispatcher.kt:42)
       at kotlinx.coroutines.scheduling.TaskImpl.run(Tasks.kt:95)
       at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:570)
       at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:750)
       at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:677)
       at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:664)

DNS failures

Fatal Exception: java.net.UnknownHostException: Unable to resolve host "www.example.com": No address associated with hostname
       at java.net.Inet6AddressImpl.lookupHostByName(Inet6AddressImpl.java:156)
       at java.net.Inet6AddressImpl.lookupAllHostAddr(Inet6AddressImpl.java:103)
       at java.net.InetAddress.getAllByName(InetAddress.java:1152)
       at okhttp3.Dns$Companion$DnsSystem.lookup(Dns.kt:49)
       at okhttp3.internal.connection.RouteSelector.resetNextInetSocketAddress(RouteSelector.kt:169)
       at okhttp3.internal.connection.RouteSelector.nextProxy(RouteSelector.kt:132)
       at okhttp3.internal.connection.RouteSelector.next(RouteSelector.kt:74)
       at okhttp3.internal.connection.RealRoutePlanner.planConnect(RealRoutePlanner.kt:147)
       at okhttp3.internal.connection.RealRoutePlanner.plan(RealRoutePlanner.kt:67)
       at okhttp3.internal.connection.SequentialExchangeFinder.find(SequentialExchangeFinder.kt:30)
       at okhttp3.internal.connection.RealCall.initExchange$okhttp(RealCall.kt:267)
       at okhttp3.internal.connection.ConnectInterceptor.intercept(ConnectInterceptor.kt:32)
       at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)
       at okhttp3.internal.cache.CacheInterceptor.intercept(CacheInterceptor.kt:95)
       at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)
       at okhttp3.internal.http.BridgeInterceptor.intercept(BridgeInterceptor.kt:84)
       at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)
       at okhttp3.internal.http.RetryAndFollowUpInterceptor.intercept(RetryAndFollowUpInterceptor.kt:65)
       at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)
       at okhttp3.internal.connection.RealCall.getResponseWithInterceptorChain$okhttp(RealCall.kt:205)
       at okhttp3.internal.connection.RealCall$AsyncCall.run(RealCall.kt:533)
       at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1137)
       at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:637)
       at java.lang.Thread.run(Thread.java:1012)
Fatal Exception: java.net.UnknownHostException: Unable to resolve host "www.example.com": No address associated with hostname
       at java.net.Inet6AddressImpl.lookupHostByName(Inet6AddressImpl.java:124)
       at java.net.Inet6AddressImpl.lookupAllHostAddr(Inet6AddressImpl.java:103)
       at java.net.InetAddress.getAllByName(InetAddress.java:1152)
       at okhttp3.Dns$Companion$DnsSystem.lookup(Dns.kt:49)
       at okhttp3.internal.connection.RouteSelector.resetNextInetSocketAddress(RouteSelector.kt:169)
       at okhttp3.internal.connection.RouteSelector.nextProxy(RouteSelector.kt:132)
       at okhttp3.internal.connection.RouteSelector.next(RouteSelector.kt:74)
       at okhttp3.internal.connection.RealRoutePlanner.planConnect(RealRoutePlanner.kt:147)
       at okhttp3.internal.connection.RealRoutePlanner.plan(RealRoutePlanner.kt:67)
       at okhttp3.internal.connection.SequentialExchangeFinder.find(SequentialExchangeFinder.kt:30)
       at okhttp3.internal.connection.RealCall.initExchange$okhttp(RealCall.kt:267)
       at okhttp3.internal.connection.ConnectInterceptor.intercept(ConnectInterceptor.kt:32)
       at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)
       at okhttp3.internal.cache.CacheInterceptor.intercept(CacheInterceptor.kt:95)
       at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)
       at okhttp3.internal.http.BridgeInterceptor.intercept(BridgeInterceptor.kt:84)
       at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)
       at okhttp3.internal.http.RetryAndFollowUpInterceptor.intercept(RetryAndFollowUpInterceptor.kt:65)
       at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)
       at okhttp3.internal.connection.RealCall.getResponseWithInterceptorChain$okhttp(RealCall.kt:205)
       at okhttp3.internal.connection.RealCall$AsyncCall.run(RealCall.kt:533)
       at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
       at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
       at java.lang.Thread.run(Thread.java:919)

Or just general socket errors

Fatal Exception: java.net.SocketException: Software caused connection abort
       at java.net.SocketOutputStream.socketWrite0(SocketOutputStream.java)
       at java.net.SocketOutputStream.socketWrite(SocketOutputStream.java:117)
       at java.net.SocketOutputStream.write(SocketOutputStream.java:161)
       at com.android.org.conscrypt.ConscryptEngineSocket$SSLOutputStream.writeToSocket(ConscryptEngineSocket.java:715)
       at com.android.org.conscrypt.ConscryptEngineSocket$SSLOutputStream.writeInternal(ConscryptEngineSocket.java:689)
       at com.android.org.conscrypt.ConscryptEngineSocket$SSLOutputStream.write(ConscryptEngineSocket.java:652)
       at okio.OutputStreamSink.write(JvmOkio.kt:57)
       at okio.AsyncTimeout$sink$1.write(AsyncTimeout.kt:99)
       at okio.internal._RealBufferedSinkKt.commonFlush(_RealBufferedSinkKt.java:183)
       at okio.RealBufferedSink.flush(RealBufferedSink.kt:133)
       at okhttp3.internal.http1.Http1ExchangeCodec.finishRequest(Http1ExchangeCodec.kt:153)
       at okhttp3.internal.connection.Exchange.finishRequest(Exchange.kt:96)
       at okhttp3.internal.http.CallServerInterceptor.intercept(CallServerInterceptor.kt:79)
       at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)
       at okhttp3.internal.connection.ConnectInterceptor.intercept(ConnectInterceptor.kt:34)
       at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)
       at okhttp3.internal.cache.CacheInterceptor.intercept(CacheInterceptor.kt:95)
       at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)
       at okhttp3.internal.http.BridgeInterceptor.intercept(BridgeInterceptor.kt:84)
       at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)
       at okhttp3.internal.http.RetryAndFollowUpInterceptor.intercept(RetryAndFollowUpInterceptor.kt:65)
       at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)
       at okhttp3.internal.connection.RealCall.getResponseWithInterceptorChain$okhttp(RealCall.kt:205)
       at okhttp3.internal.connection.RealCall$AsyncCall.run(RealCall.kt:533)
       at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
       at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
       at java.lang.Thread.run(Thread.java:923)

What did you expect to happen?

The exception should be thrown from the requestFunction parameter of SuspendResponseConverter. wrapSuspendResponse at the moment it's obviously being thrown elsewhere, and so makes it impossible to handle.

Is there anything else we need to know about?

No response

Foso commented 1 year ago

Hi, thank you for your bug report

Foso commented 1 year ago

The issue is fixed v1.0.0