Skip to content

Commit 9acbf93

Browse files
feat(client): add connection pooling option
1 parent fba86c8 commit 9acbf93

4 files changed

Lines changed: 149 additions & 0 deletions

File tree

README.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -560,6 +560,25 @@ LangsmithClient client = LangsmithOkHttpClient.builder()
560560
.build();
561561
```
562562

563+
### Connection pooling
564+
565+
To customize the underlying OkHttp connection pool, configure the client using the `maxIdleConnections` and `keepAliveDuration` methods:
566+
567+
```java
568+
import com.langchain.smith.client.LangsmithClient;
569+
import com.langchain.smith.client.okhttp.LangsmithOkHttpClient;
570+
import java.time.Duration;
571+
572+
LangsmithClient client = LangsmithOkHttpClient.builder()
573+
.fromEnv()
574+
// If `maxIdleConnections` is set, then `keepAliveDuration` must be set, and vice versa.
575+
.maxIdleConnections(10)
576+
.keepAliveDuration(Duration.ofMinutes(2))
577+
.build();
578+
```
579+
580+
If both options are unset, OkHttp's default connection pool settings are used.
581+
563582
### HTTPS
564583

565584
> [!NOTE]

langsmith-java-client-okhttp/src/main/kotlin/com/langchain/smith/client/okhttp/LangsmithOkHttpClient.kt

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@ class LangsmithOkHttpClient private constructor() {
4949
private var clientOptions: ClientOptions.Builder = ClientOptions.builder()
5050
private var dispatcherExecutorService: ExecutorService? = null
5151
private var proxy: Proxy? = null
52+
private var maxIdleConnections: Int? = null
53+
private var keepAliveDuration: Duration? = null
5254
private var sslSocketFactory: SSLSocketFactory? = null
5355
private var trustManager: X509TrustManager? = null
5456
private var hostnameVerifier: HostnameVerifier? = null
@@ -77,6 +79,46 @@ class LangsmithOkHttpClient private constructor() {
7779
/** Alias for calling [Builder.proxy] with `proxy.orElse(null)`. */
7880
fun proxy(proxy: Optional<Proxy>) = proxy(proxy.getOrNull())
7981

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

langsmith-java-client-okhttp/src/main/kotlin/com/langchain/smith/client/okhttp/LangsmithOkHttpClientAsync.kt

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@ class LangsmithOkHttpClientAsync private constructor() {
4949
private var clientOptions: ClientOptions.Builder = ClientOptions.builder()
5050
private var dispatcherExecutorService: ExecutorService? = null
5151
private var proxy: Proxy? = null
52+
private var maxIdleConnections: Int? = null
53+
private var keepAliveDuration: Duration? = null
5254
private var sslSocketFactory: SSLSocketFactory? = null
5355
private var trustManager: X509TrustManager? = null
5456
private var hostnameVerifier: HostnameVerifier? = null
@@ -77,6 +79,46 @@ class LangsmithOkHttpClientAsync private constructor() {
7779
/** Alias for calling [Builder.proxy] with `proxy.orElse(null)`. */
7880
fun proxy(proxy: Optional<Proxy>) = proxy(proxy.getOrNull())
7981

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

langsmith-java-client-okhttp/src/main/kotlin/com/langchain/smith/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
@@ -205,6 +207,8 @@ internal constructor(@JvmSynthetic internal val okHttpClient: okhttp3.OkHttpClie
205207

206208
private var timeout: Timeout = Timeout.default()
207209
private var proxy: Proxy? = null
210+
private var maxIdleConnections: Int? = null
211+
private var keepAliveDuration: Duration? = null
208212
private var dispatcherExecutorService: ExecutorService? = null
209213
private var sslSocketFactory: SSLSocketFactory? = null
210214
private var trustManager: X509TrustManager? = null
@@ -216,6 +220,28 @@ internal constructor(@JvmSynthetic internal val okHttpClient: okhttp3.OkHttpClie
216220

217221
fun proxy(proxy: Proxy?) = apply { this.proxy = proxy }
218222

223+
/**
224+
* Sets the maximum number of idle connections kept by the underlying [ConnectionPool].
225+
*
226+
* If this is set, then [keepAliveDuration] must also be set.
227+
*
228+
* If unset, then OkHttp's default is used.
229+
*/
230+
fun maxIdleConnections(maxIdleConnections: Int?) = apply {
231+
this.maxIdleConnections = maxIdleConnections
232+
}
233+
234+
/**
235+
* Sets the keep-alive duration for idle connections in the underlying [ConnectionPool].
236+
*
237+
* If this is set, then [maxIdleConnections] must also be set.
238+
*
239+
* If unset, then OkHttp's default is used.
240+
*/
241+
fun keepAliveDuration(keepAliveDuration: Duration?) = apply {
242+
this.keepAliveDuration = keepAliveDuration
243+
}
244+
219245
fun dispatcherExecutorService(dispatcherExecutorService: ExecutorService?) = apply {
220246
this.dispatcherExecutorService = dispatcherExecutorService
221247
}
@@ -245,6 +271,22 @@ internal constructor(@JvmSynthetic internal val okHttpClient: okhttp3.OkHttpClie
245271
.apply {
246272
dispatcherExecutorService?.let { dispatcher(Dispatcher(it)) }
247273

274+
val maxIdleConnections = maxIdleConnections
275+
val keepAliveDuration = keepAliveDuration
276+
if (maxIdleConnections != null && keepAliveDuration != null) {
277+
connectionPool(
278+
ConnectionPool(
279+
maxIdleConnections,
280+
keepAliveDuration.toNanos(),
281+
TimeUnit.NANOSECONDS,
282+
)
283+
)
284+
} else {
285+
check((maxIdleConnections != null) == (keepAliveDuration != null)) {
286+
"Both or none of `maxIdleConnections` and `keepAliveDuration` must be set, but only one was set"
287+
}
288+
}
289+
248290
val sslSocketFactory = sslSocketFactory
249291
val trustManager = trustManager
250292
if (sslSocketFactory != null && trustManager != null) {

0 commit comments

Comments
 (0)