Skip to content

Commit 4d3b414

Browse files
feat(client): allow configuring timeouts granularly (#470)
Note that previously the `timeout(Duration)` method on the client and `RequestOptions` corresponded to connect, read, write, and request timeout. Now it only corresponds to the request timeout. Use the new `timeout(Timeout)` method to configure other timeout values granularly.
1 parent a308954 commit 4d3b414

58 files changed

Lines changed: 420 additions & 111 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

finch-java-client-okhttp/src/main/kotlin/com/tryfinch/api/client/okhttp/FinchOkHttpClient.kt

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import com.fasterxml.jackson.databind.json.JsonMapper
66
import com.tryfinch.api.client.FinchClient
77
import com.tryfinch.api.client.FinchClientImpl
88
import com.tryfinch.api.core.ClientOptions
9+
import com.tryfinch.api.core.Timeout
910
import com.tryfinch.api.core.http.Headers
1011
import com.tryfinch.api.core.http.QueryParams
1112
import java.net.Proxy
@@ -27,8 +28,7 @@ class FinchOkHttpClient private constructor() {
2728

2829
private var clientOptions: ClientOptions.Builder = ClientOptions.builder()
2930
private var baseUrl: String = ClientOptions.PRODUCTION_URL
30-
// The default timeout for the client is 1 minute.
31-
private var timeout: Duration = Duration.ofSeconds(60)
31+
private var timeout: Timeout = Timeout.default()
3232
private var proxy: Proxy? = null
3333

3434
fun baseUrl(baseUrl: String) = apply {
@@ -120,7 +120,19 @@ class FinchOkHttpClient private constructor() {
120120
clientOptions.removeAllQueryParams(keys)
121121
}
122122

123-
fun timeout(timeout: Duration) = apply { this.timeout = timeout }
123+
fun timeout(timeout: Timeout) = apply {
124+
clientOptions.timeout(timeout)
125+
this.timeout = timeout
126+
}
127+
128+
/**
129+
* Sets the maximum time allowed for a complete HTTP call, not including retries.
130+
*
131+
* See [Timeout.request] for more details.
132+
*
133+
* For fine-grained control, pass a [Timeout] object.
134+
*/
135+
fun timeout(timeout: Duration) = timeout(Timeout.builder().request(timeout).build())
124136

125137
fun maxRetries(maxRetries: Int) = apply { clientOptions.maxRetries(maxRetries) }
126138

finch-java-client-okhttp/src/main/kotlin/com/tryfinch/api/client/okhttp/FinchOkHttpClientAsync.kt

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import com.fasterxml.jackson.databind.json.JsonMapper
66
import com.tryfinch.api.client.FinchClientAsync
77
import com.tryfinch.api.client.FinchClientAsyncImpl
88
import com.tryfinch.api.core.ClientOptions
9+
import com.tryfinch.api.core.Timeout
910
import com.tryfinch.api.core.http.Headers
1011
import com.tryfinch.api.core.http.QueryParams
1112
import java.net.Proxy
@@ -27,8 +28,7 @@ class FinchOkHttpClientAsync private constructor() {
2728

2829
private var clientOptions: ClientOptions.Builder = ClientOptions.builder()
2930
private var baseUrl: String = ClientOptions.PRODUCTION_URL
30-
// The default timeout for the client is 1 minute.
31-
private var timeout: Duration = Duration.ofSeconds(60)
31+
private var timeout: Timeout = Timeout.default()
3232
private var proxy: Proxy? = null
3333

3434
fun baseUrl(baseUrl: String) = apply {
@@ -120,7 +120,19 @@ class FinchOkHttpClientAsync private constructor() {
120120
clientOptions.removeAllQueryParams(keys)
121121
}
122122

123-
fun timeout(timeout: Duration) = apply { this.timeout = timeout }
123+
fun timeout(timeout: Timeout) = apply {
124+
clientOptions.timeout(timeout)
125+
this.timeout = timeout
126+
}
127+
128+
/**
129+
* Sets the maximum time allowed for a complete HTTP call, not including retries.
130+
*
131+
* See [Timeout.request] for more details.
132+
*
133+
* For fine-grained control, pass a [Timeout] object.
134+
*/
135+
fun timeout(timeout: Duration) = timeout(Timeout.builder().request(timeout).build())
124136

125137
fun maxRetries(maxRetries: Int) = apply { clientOptions.maxRetries(maxRetries) }
126138

finch-java-client-okhttp/src/main/kotlin/com/tryfinch/api/client/okhttp/OkHttpClient.kt

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package com.tryfinch.api.client.okhttp
22

33
import com.tryfinch.api.core.RequestOptions
4+
import com.tryfinch.api.core.Timeout
45
import com.tryfinch.api.core.checkRequired
56
import com.tryfinch.api.core.http.Headers
67
import com.tryfinch.api.core.http.HttpClient
@@ -88,13 +89,12 @@ private constructor(private val okHttpClient: okhttp3.OkHttpClient, private val
8889
)
8990
}
9091

91-
val timeout = requestOptions.timeout
92-
if (timeout != null) {
92+
requestOptions.timeout?.let {
9393
clientBuilder
94-
.connectTimeout(timeout)
95-
.readTimeout(timeout)
96-
.writeTimeout(timeout)
97-
.callTimeout(if (timeout.seconds == 0L) timeout else timeout.plusSeconds(30))
94+
.connectTimeout(it.connect())
95+
.readTimeout(it.read())
96+
.writeTimeout(it.write())
97+
.callTimeout(it.request())
9898
}
9999

100100
val client = clientBuilder.build()
@@ -195,23 +195,24 @@ private constructor(private val okHttpClient: okhttp3.OkHttpClient, private val
195195
class Builder internal constructor() {
196196

197197
private var baseUrl: HttpUrl? = null
198-
// The default timeout is 1 minute.
199-
private var timeout: Duration = Duration.ofSeconds(60)
198+
private var timeout: Timeout = Timeout.default()
200199
private var proxy: Proxy? = null
201200

202201
fun baseUrl(baseUrl: String) = apply { this.baseUrl = baseUrl.toHttpUrl() }
203202

204-
fun timeout(timeout: Duration) = apply { this.timeout = timeout }
203+
fun timeout(timeout: Timeout) = apply { this.timeout = timeout }
204+
205+
fun timeout(timeout: Duration) = timeout(Timeout.builder().request(timeout).build())
205206

206207
fun proxy(proxy: Proxy?) = apply { this.proxy = proxy }
207208

208209
fun build(): OkHttpClient =
209210
OkHttpClient(
210211
okhttp3.OkHttpClient.Builder()
211-
.connectTimeout(timeout)
212-
.readTimeout(timeout)
213-
.writeTimeout(timeout)
214-
.callTimeout(if (timeout.seconds == 0L) timeout else timeout.plusSeconds(30))
212+
.connectTimeout(timeout.connect())
213+
.readTimeout(timeout.read())
214+
.writeTimeout(timeout.write())
215+
.callTimeout(timeout.request())
215216
.proxy(proxy)
216217
.build(),
217218
checkRequired("baseUrl", baseUrl),

finch-java-core/src/main/kotlin/com/tryfinch/api/core/ClientOptions.kt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ private constructor(
2222
@get:JvmName("headers") val headers: Headers,
2323
@get:JvmName("queryParams") val queryParams: QueryParams,
2424
@get:JvmName("responseValidation") val responseValidation: Boolean,
25+
@get:JvmName("timeout") val timeout: Timeout,
2526
@get:JvmName("maxRetries") val maxRetries: Int,
2627
@get:JvmName("accessToken") val accessToken: String?,
2728
@get:JvmName("clientId") val clientId: String?,
@@ -50,6 +51,7 @@ private constructor(
5051
private var headers: Headers.Builder = Headers.builder()
5152
private var queryParams: QueryParams.Builder = QueryParams.builder()
5253
private var responseValidation: Boolean = false
54+
private var timeout: Timeout = Timeout.default()
5355
private var maxRetries: Int = 2
5456
private var accessToken: String? = null
5557
private var clientId: String? = null
@@ -65,6 +67,7 @@ private constructor(
6567
headers = clientOptions.headers.toBuilder()
6668
queryParams = clientOptions.queryParams.toBuilder()
6769
responseValidation = clientOptions.responseValidation
70+
timeout = clientOptions.timeout
6871
maxRetries = clientOptions.maxRetries
6972
accessToken = clientOptions.accessToken
7073
clientId = clientOptions.clientId
@@ -84,6 +87,8 @@ private constructor(
8487
this.responseValidation = responseValidation
8588
}
8689

90+
fun timeout(timeout: Timeout) = apply { this.timeout = timeout }
91+
8792
fun maxRetries(maxRetries: Int) = apply { this.maxRetries = maxRetries }
8893

8994
fun accessToken(accessToken: String?) = apply { this.accessToken = accessToken }
@@ -235,6 +240,7 @@ private constructor(
235240
headers.build(),
236241
queryParams.build(),
237242
responseValidation,
243+
timeout,
238244
maxRetries,
239245
accessToken,
240246
clientId,

finch-java-core/src/main/kotlin/com/tryfinch/api/core/RequestOptions.kt

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,36 +2,45 @@ package com.tryfinch.api.core
22

33
import java.time.Duration
44

5-
class RequestOptions private constructor(val responseValidation: Boolean?, val timeout: Duration?) {
6-
fun applyDefaults(options: RequestOptions): RequestOptions {
7-
return RequestOptions(
8-
responseValidation = this.responseValidation ?: options.responseValidation,
9-
timeout = this.timeout ?: options.timeout,
10-
)
11-
}
5+
class RequestOptions private constructor(val responseValidation: Boolean?, val timeout: Timeout?) {
126

137
companion object {
148

159
private val NONE = builder().build()
1610

1711
@JvmStatic fun none() = NONE
1812

13+
@JvmSynthetic
14+
internal fun from(clientOptions: ClientOptions): RequestOptions =
15+
builder()
16+
.responseValidation(clientOptions.responseValidation)
17+
.timeout(clientOptions.timeout)
18+
.build()
19+
1920
@JvmStatic fun builder() = Builder()
2021
}
2122

23+
fun applyDefaults(options: RequestOptions): RequestOptions =
24+
RequestOptions(
25+
responseValidation = responseValidation ?: options.responseValidation,
26+
timeout =
27+
if (options.timeout != null && timeout != null) timeout.assign(options.timeout)
28+
else timeout ?: options.timeout,
29+
)
30+
2231
class Builder internal constructor() {
2332

2433
private var responseValidation: Boolean? = null
25-
private var timeout: Duration? = null
34+
private var timeout: Timeout? = null
2635

2736
fun responseValidation(responseValidation: Boolean) = apply {
2837
this.responseValidation = responseValidation
2938
}
3039

31-
fun timeout(timeout: Duration) = apply { this.timeout = timeout }
40+
fun timeout(timeout: Timeout) = apply { this.timeout = timeout }
3241

33-
fun build(): RequestOptions {
34-
return RequestOptions(responseValidation, timeout)
35-
}
42+
fun timeout(timeout: Duration) = timeout(Timeout.builder().request(timeout).build())
43+
44+
fun build(): RequestOptions = RequestOptions(responseValidation, timeout)
3645
}
3746
}

0 commit comments

Comments
 (0)