Skip to content

Commit 3ad0fbc

Browse files
feat(client): add connection pooling option
1 parent 1939ec1 commit 3ad0fbc

File tree

4 files changed

+149
-0
lines changed

4 files changed

+149
-0
lines changed

README.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -342,6 +342,25 @@ CasParserClient client = CasParserOkHttpClient.builder()
342342
.build();
343343
```
344344

345+
### Connection pooling
346+
347+
To customize the underlying OkHttp connection pool, configure the client using the `maxIdleConnections` and `keepAliveDuration` methods:
348+
349+
```java
350+
import com.cas_parser.api.client.CasParserClient;
351+
import com.cas_parser.api.client.okhttp.CasParserOkHttpClient;
352+
import java.time.Duration;
353+
354+
CasParserClient client = CasParserOkHttpClient.builder()
355+
.fromEnv()
356+
// If `maxIdleConnections` is set, then `keepAliveDuration` must be set, and vice versa.
357+
.maxIdleConnections(10)
358+
.keepAliveDuration(Duration.ofMinutes(2))
359+
.build();
360+
```
361+
362+
If both options are unset, OkHttp's default connection pool settings are used.
363+
345364
### HTTPS
346365

347366
> [!NOTE]

cas-parser-java-client-okhttp/src/main/kotlin/com/cas_parser/api/client/okhttp/CasParserOkHttpClient.kt

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ class CasParserOkHttpClient private constructor() {
4747
private var clientOptions: ClientOptions.Builder = ClientOptions.builder()
4848
private var dispatcherExecutorService: ExecutorService? = null
4949
private var proxy: Proxy? = null
50+
private var maxIdleConnections: Int? = null
51+
private var keepAliveDuration: Duration? = null
5052
private var sslSocketFactory: SSLSocketFactory? = null
5153
private var trustManager: X509TrustManager? = null
5254
private var hostnameVerifier: HostnameVerifier? = null
@@ -75,6 +77,46 @@ class CasParserOkHttpClient private constructor() {
7577
/** Alias for calling [Builder.proxy] with `proxy.orElse(null)`. */
7678
fun proxy(proxy: Optional<Proxy>) = proxy(proxy.getOrNull())
7779

80+
/**
81+
* The maximum number of idle connections kept by the underlying OkHttp connection pool.
82+
*
83+
* If this is set, then [keepAliveDuration] must also be set.
84+
*
85+
* If unset, then OkHttp's default is used.
86+
*/
87+
fun maxIdleConnections(maxIdleConnections: Int?) = apply {
88+
this.maxIdleConnections = maxIdleConnections
89+
}
90+
91+
/**
92+
* Alias for [Builder.maxIdleConnections].
93+
*
94+
* This unboxed primitive overload exists for backwards compatibility.
95+
*/
96+
fun maxIdleConnections(maxIdleConnections: Int) =
97+
maxIdleConnections(maxIdleConnections as Int?)
98+
99+
/**
100+
* Alias for calling [Builder.maxIdleConnections] with `maxIdleConnections.orElse(null)`.
101+
*/
102+
fun maxIdleConnections(maxIdleConnections: Optional<Int>) =
103+
maxIdleConnections(maxIdleConnections.getOrNull())
104+
105+
/**
106+
* The keep-alive duration for idle connections in the underlying OkHttp connection pool.
107+
*
108+
* If this is set, then [maxIdleConnections] must also be set.
109+
*
110+
* If unset, then OkHttp's default is used.
111+
*/
112+
fun keepAliveDuration(keepAliveDuration: Duration?) = apply {
113+
this.keepAliveDuration = keepAliveDuration
114+
}
115+
116+
/** Alias for calling [Builder.keepAliveDuration] with `keepAliveDuration.orElse(null)`. */
117+
fun keepAliveDuration(keepAliveDuration: Optional<Duration>) =
118+
keepAliveDuration(keepAliveDuration.getOrNull())
119+
78120
/**
79121
* The socket factory used to secure HTTPS connections.
80122
*
@@ -328,6 +370,8 @@ class CasParserOkHttpClient private constructor() {
328370
OkHttpClient.builder()
329371
.timeout(clientOptions.timeout())
330372
.proxy(proxy)
373+
.maxIdleConnections(maxIdleConnections)
374+
.keepAliveDuration(keepAliveDuration)
331375
.dispatcherExecutorService(dispatcherExecutorService)
332376
.sslSocketFactory(sslSocketFactory)
333377
.trustManager(trustManager)

cas-parser-java-client-okhttp/src/main/kotlin/com/cas_parser/api/client/okhttp/CasParserOkHttpClientAsync.kt

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ class CasParserOkHttpClientAsync private constructor() {
4747
private var clientOptions: ClientOptions.Builder = ClientOptions.builder()
4848
private var dispatcherExecutorService: ExecutorService? = null
4949
private var proxy: Proxy? = null
50+
private var maxIdleConnections: Int? = null
51+
private var keepAliveDuration: Duration? = null
5052
private var sslSocketFactory: SSLSocketFactory? = null
5153
private var trustManager: X509TrustManager? = null
5254
private var hostnameVerifier: HostnameVerifier? = null
@@ -75,6 +77,46 @@ class CasParserOkHttpClientAsync private constructor() {
7577
/** Alias for calling [Builder.proxy] with `proxy.orElse(null)`. */
7678
fun proxy(proxy: Optional<Proxy>) = proxy(proxy.getOrNull())
7779

80+
/**
81+
* The maximum number of idle connections kept by the underlying OkHttp connection pool.
82+
*
83+
* If this is set, then [keepAliveDuration] must also be set.
84+
*
85+
* If unset, then OkHttp's default is used.
86+
*/
87+
fun maxIdleConnections(maxIdleConnections: Int?) = apply {
88+
this.maxIdleConnections = maxIdleConnections
89+
}
90+
91+
/**
92+
* Alias for [Builder.maxIdleConnections].
93+
*
94+
* This unboxed primitive overload exists for backwards compatibility.
95+
*/
96+
fun maxIdleConnections(maxIdleConnections: Int) =
97+
maxIdleConnections(maxIdleConnections as Int?)
98+
99+
/**
100+
* Alias for calling [Builder.maxIdleConnections] with `maxIdleConnections.orElse(null)`.
101+
*/
102+
fun maxIdleConnections(maxIdleConnections: Optional<Int>) =
103+
maxIdleConnections(maxIdleConnections.getOrNull())
104+
105+
/**
106+
* The keep-alive duration for idle connections in the underlying OkHttp connection pool.
107+
*
108+
* If this is set, then [maxIdleConnections] must also be set.
109+
*
110+
* If unset, then OkHttp's default is used.
111+
*/
112+
fun keepAliveDuration(keepAliveDuration: Duration?) = apply {
113+
this.keepAliveDuration = keepAliveDuration
114+
}
115+
116+
/** Alias for calling [Builder.keepAliveDuration] with `keepAliveDuration.orElse(null)`. */
117+
fun keepAliveDuration(keepAliveDuration: Optional<Duration>) =
118+
keepAliveDuration(keepAliveDuration.getOrNull())
119+
78120
/**
79121
* The socket factory used to secure HTTPS connections.
80122
*
@@ -328,6 +370,8 @@ class CasParserOkHttpClientAsync private constructor() {
328370
OkHttpClient.builder()
329371
.timeout(clientOptions.timeout())
330372
.proxy(proxy)
373+
.maxIdleConnections(maxIdleConnections)
374+
.keepAliveDuration(keepAliveDuration)
331375
.dispatcherExecutorService(dispatcherExecutorService)
332376
.sslSocketFactory(sslSocketFactory)
333377
.trustManager(trustManager)

cas-parser-java-client-okhttp/src/main/kotlin/com/cas_parser/api/client/okhttp/OkHttpClient.kt

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,13 @@ import java.time.Duration
1616
import java.util.concurrent.CancellationException
1717
import java.util.concurrent.CompletableFuture
1818
import java.util.concurrent.ExecutorService
19+
import java.util.concurrent.TimeUnit
1920
import javax.net.ssl.HostnameVerifier
2021
import javax.net.ssl.SSLSocketFactory
2122
import javax.net.ssl.X509TrustManager
2223
import okhttp3.Call
2324
import okhttp3.Callback
25+
import okhttp3.ConnectionPool
2426
import okhttp3.Dispatcher
2527
import okhttp3.HttpUrl.Companion.toHttpUrl
2628
import okhttp3.MediaType
@@ -200,6 +202,8 @@ internal constructor(@JvmSynthetic internal val okHttpClient: okhttp3.OkHttpClie
200202

201203
private var timeout: Timeout = Timeout.default()
202204
private var proxy: Proxy? = null
205+
private var maxIdleConnections: Int? = null
206+
private var keepAliveDuration: Duration? = null
203207
private var dispatcherExecutorService: ExecutorService? = null
204208
private var sslSocketFactory: SSLSocketFactory? = null
205209
private var trustManager: X509TrustManager? = null
@@ -211,6 +215,28 @@ internal constructor(@JvmSynthetic internal val okHttpClient: okhttp3.OkHttpClie
211215

212216
fun proxy(proxy: Proxy?) = apply { this.proxy = proxy }
213217

218+
/**
219+
* Sets the maximum number of idle connections kept by the underlying [ConnectionPool].
220+
*
221+
* If this is set, then [keepAliveDuration] must also be set.
222+
*
223+
* If unset, then OkHttp's default is used.
224+
*/
225+
fun maxIdleConnections(maxIdleConnections: Int?) = apply {
226+
this.maxIdleConnections = maxIdleConnections
227+
}
228+
229+
/**
230+
* Sets the keep-alive duration for idle connections in the underlying [ConnectionPool].
231+
*
232+
* If this is set, then [maxIdleConnections] must also be set.
233+
*
234+
* If unset, then OkHttp's default is used.
235+
*/
236+
fun keepAliveDuration(keepAliveDuration: Duration?) = apply {
237+
this.keepAliveDuration = keepAliveDuration
238+
}
239+
214240
fun dispatcherExecutorService(dispatcherExecutorService: ExecutorService?) = apply {
215241
this.dispatcherExecutorService = dispatcherExecutorService
216242
}
@@ -240,6 +266,22 @@ internal constructor(@JvmSynthetic internal val okHttpClient: okhttp3.OkHttpClie
240266
.apply {
241267
dispatcherExecutorService?.let { dispatcher(Dispatcher(it)) }
242268

269+
val maxIdleConnections = maxIdleConnections
270+
val keepAliveDuration = keepAliveDuration
271+
if (maxIdleConnections != null && keepAliveDuration != null) {
272+
connectionPool(
273+
ConnectionPool(
274+
maxIdleConnections,
275+
keepAliveDuration.toNanos(),
276+
TimeUnit.NANOSECONDS,
277+
)
278+
)
279+
} else {
280+
check((maxIdleConnections != null) == (keepAliveDuration != null)) {
281+
"Both or none of `maxIdleConnections` and `keepAliveDuration` must be set, but only one was set"
282+
}
283+
}
284+
243285
val sslSocketFactory = sslSocketFactory
244286
val trustManager = trustManager
245287
if (sslSocketFactory != null && trustManager != null) {

0 commit comments

Comments
 (0)