Skip to content

Commit 8bddd84

Browse files
authored
feat(rt)!:introduce maxConcurrency HTTP setting and rename OkHttp maxConnectionsPerHost (#899)
1 parent 2be0bea commit 8bddd84

File tree

7 files changed

+44
-17
lines changed

7 files changed

+44
-17
lines changed
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"id": "c5f04082-06d1-4425-b7b9-b1ac2b9b8edd",
3+
"type": "feature",
4+
"description": "BREAKING: introduce `maxConcurrency` HTTP engine setting and rename OkHttp specific `maxConnectionsPerHost` to `maxConcurrencyPerHost`.",
5+
"issues": [
6+
"awslabs/smithy-kotlin#898"
7+
]
8+
}

runtime/protocol/http-client-engines/http-client-engine-crt/common/src/aws/smithy/kotlin/runtime/http/engine/crt/CrtHttpEngine.kt

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,11 @@ import aws.smithy.kotlin.runtime.io.internal.SdkDispatchers
2626
import aws.smithy.kotlin.runtime.operation.ExecutionContext
2727
import aws.smithy.kotlin.runtime.telemetry.logging.logger
2828
import aws.smithy.kotlin.runtime.time.Instant
29-
import kotlinx.coroutines.job
29+
import kotlinx.coroutines.*
3030
import kotlinx.coroutines.sync.Mutex
31+
import kotlinx.coroutines.sync.Semaphore
3132
import kotlinx.coroutines.sync.withLock
32-
import kotlinx.coroutines.withContext
33-
import kotlinx.coroutines.withTimeoutOrNull
33+
import kotlinx.coroutines.sync.withPermit
3434
import aws.sdk.kotlin.crt.io.TlsContext as CrtTlsContext
3535
import aws.sdk.kotlin.crt.io.TlsVersion as CrtTlsVersion
3636
import aws.smithy.kotlin.runtime.config.TlsVersion as SdkTlsVersion
@@ -83,15 +83,17 @@ public class CrtHttpEngine(public override val config: CrtHttpEngineConfig) : Ht
8383
connectTimeoutMs = config.connectTimeout.inWholeMilliseconds.toInt(),
8484
)
8585
initialWindowSize = config.initialWindowSizeBytes
86+
// FIXME - given managers are _per host_ the maxConnections parameter is not actually respected here
8687
maxConnections = config.maxConnections.toInt()
8788
maxConnectionIdleMs = config.connectionIdleTimeout.inWholeMilliseconds
8889
}
8990

9091
// connection managers are per host
9192
private val connManagers = mutableMapOf<String, HttpClientConnectionManager>()
9293
private val mutex = Mutex()
94+
private val requestLimiter = Semaphore(config.maxConcurrency.toInt())
9395

94-
override suspend fun roundTrip(context: ExecutionContext, request: HttpRequest): HttpCall {
96+
override suspend fun roundTrip(context: ExecutionContext, request: HttpRequest): HttpCall = requestLimiter.withPermit {
9597
val callContext = callContext()
9698
val logger = callContext.logger<CrtHttpEngine>()
9799
val proxyConfig = config.proxySelector.select(request.url)

runtime/protocol/http-client-engines/http-client-engine-okhttp/api/http-client-engine-okhttp.api

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,15 @@ public final class aws/smithy/kotlin/runtime/http/engine/okhttp/OkHttpEngine$Com
1515
public final class aws/smithy/kotlin/runtime/http/engine/okhttp/OkHttpEngineConfig : aws/smithy/kotlin/runtime/http/engine/HttpClientEngineConfigImpl {
1616
public static final field Companion Laws/smithy/kotlin/runtime/http/engine/okhttp/OkHttpEngineConfig$Companion;
1717
public synthetic fun <init> (Laws/smithy/kotlin/runtime/http/engine/okhttp/OkHttpEngineConfig$Builder;Lkotlin/jvm/internal/DefaultConstructorMarker;)V
18-
public final fun getMaxConnectionsPerHost-pVg5ArA ()I
18+
public final fun getMaxConcurrencyPerHost-pVg5ArA ()I
1919
public fun toBuilderApplicator ()Lkotlin/jvm/functions/Function1;
2020
}
2121

2222
public final class aws/smithy/kotlin/runtime/http/engine/okhttp/OkHttpEngineConfig$Builder : aws/smithy/kotlin/runtime/http/engine/HttpClientEngineConfigImpl$BuilderImpl {
2323
public fun <init> ()V
24-
public final fun getMaxConnectionsPerHost-0hXNFcg ()Lkotlin/UInt;
24+
public final fun getMaxConcurrencyPerHost-0hXNFcg ()Lkotlin/UInt;
2525
public fun getTelemetryProvider ()Laws/smithy/kotlin/runtime/telemetry/TelemetryProvider;
26-
public final fun setMaxConnectionsPerHost-ExVfyTY (Lkotlin/UInt;)V
26+
public final fun setMaxConcurrencyPerHost-ExVfyTY (Lkotlin/UInt;)V
2727
public fun setTelemetryProvider (Laws/smithy/kotlin/runtime/telemetry/TelemetryProvider;)V
2828
}
2929

runtime/protocol/http-client-engines/http-client-engine-okhttp/jvm/src/aws/smithy/kotlin/runtime/http/engine/okhttp/OkHttpEngine.kt

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ private fun OkHttpEngineConfig.buildClient(metrics: HttpClientMetrics): OkHttpCl
9595

9696
// FIXME - register a [ConnectionListener](https://github.com/square/okhttp/blob/master/okhttp/src/jvmMain/kotlin/okhttp3/ConnectionListener.kt#L27)
9797
// when a new okhttp release is cut that contains this abstraction and wireup connection uptime metrics
98+
// FIXME - with that ConnectionListener implement our own max connections gate?
9899

99100
// use our own pool configured with the timeout settings taken from config
100101
val pool = ConnectionPool(
@@ -104,11 +105,9 @@ private fun OkHttpEngineConfig.buildClient(metrics: HttpClientMetrics): OkHttpCl
104105
)
105106
connectionPool(pool)
106107

107-
// Configure a dispatcher that uses maxConnections as a proxy for maxRequests. Note that this isn't precisely
108-
// the same since some protocols (e.g., HTTP2) may use a single connection for multiple requests.
109108
val dispatcher = Dispatcher().apply {
110-
maxRequests = config.maxConnections.toInt()
111-
maxRequestsPerHost = config.maxConnectionsPerHost.toInt()
109+
maxRequests = config.maxConcurrency.toInt()
110+
maxRequestsPerHost = config.maxConcurrencyPerHost.toInt()
112111
}
113112
dispatcher(dispatcher)
114113

runtime/protocol/http-client-engines/http-client-engine-okhttp/jvm/src/aws/smithy/kotlin/runtime/http/engine/okhttp/OkHttpEngineConfig.kt

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,15 +29,15 @@ public class OkHttpEngineConfig private constructor(builder: Builder) : HttpClie
2929
}
3030

3131
/**
32-
* The maximum number of connections to open to a single host.
32+
* The maximum number of requests to execute concurrently for a single host.
3333
*/
34-
public val maxConnectionsPerHost: UInt = builder.maxConnectionsPerHost ?: builder.maxConnections
34+
public val maxConcurrencyPerHost: UInt = builder.maxConcurrencyPerHost ?: builder.maxConcurrency
3535

3636
override fun toBuilderApplicator(): HttpClientEngineConfig.Builder.() -> Unit = {
3737
super.toBuilderApplicator()()
3838

3939
if (this is Builder) {
40-
maxConnectionsPerHost = this@OkHttpEngineConfig.maxConnectionsPerHost
40+
maxConcurrencyPerHost = this@OkHttpEngineConfig.maxConcurrencyPerHost
4141
}
4242
}
4343

@@ -46,9 +46,9 @@ public class OkHttpEngineConfig private constructor(builder: Builder) : HttpClie
4646
*/
4747
public class Builder : BuilderImpl() {
4848
/**
49-
* The maximum number of connections to open to a single host. Defaults to [maxConnections].
49+
* The maximum number of requests to execute concurrently for a single host. Defaults to [maxConcurrency].
5050
*/
51-
public var maxConnectionsPerHost: UInt? = null
51+
public var maxConcurrencyPerHost: UInt? = null
5252

5353
override var telemetryProvider: TelemetryProvider = TelemetryProvider.Global
5454
}

runtime/protocol/http-client/api/http-client.api

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ public abstract interface class aws/smithy/kotlin/runtime/http/engine/HttpClient
7373
public abstract fun getConnectionAcquireTimeout-UwyO8pc ()J
7474
public abstract fun getConnectionIdleTimeout-UwyO8pc ()J
7575
public abstract fun getHostResolver ()Laws/smithy/kotlin/runtime/net/HostResolver;
76+
public abstract fun getMaxConcurrency-pVg5ArA ()I
7677
public abstract fun getMaxConnections-pVg5ArA ()I
7778
public abstract fun getProxySelector ()Laws/smithy/kotlin/runtime/http/engine/ProxySelector;
7879
public abstract fun getSocketReadTimeout-UwyO8pc ()J
@@ -87,6 +88,7 @@ public abstract interface class aws/smithy/kotlin/runtime/http/engine/HttpClient
8788
public abstract fun getConnectionAcquireTimeout-UwyO8pc ()J
8889
public abstract fun getConnectionIdleTimeout-UwyO8pc ()J
8990
public abstract fun getHostResolver ()Laws/smithy/kotlin/runtime/net/HostResolver;
91+
public abstract fun getMaxConcurrency-pVg5ArA ()I
9092
public abstract fun getMaxConnections-pVg5ArA ()I
9193
public abstract fun getProxySelector ()Laws/smithy/kotlin/runtime/http/engine/ProxySelector;
9294
public abstract fun getSocketReadTimeout-UwyO8pc ()J
@@ -97,6 +99,7 @@ public abstract interface class aws/smithy/kotlin/runtime/http/engine/HttpClient
9799
public abstract fun setConnectionAcquireTimeout-LRDsOJo (J)V
98100
public abstract fun setConnectionIdleTimeout-LRDsOJo (J)V
99101
public abstract fun setHostResolver (Laws/smithy/kotlin/runtime/net/HostResolver;)V
102+
public abstract fun setMaxConcurrency-WZ4Q5Ns (I)V
100103
public abstract fun setMaxConnections-WZ4Q5Ns (I)V
101104
public abstract fun setProxySelector (Laws/smithy/kotlin/runtime/http/engine/ProxySelector;)V
102105
public abstract fun setSocketReadTimeout-LRDsOJo (J)V

runtime/protocol/http-client/common/src/aws/smithy/kotlin/runtime/http/engine/HttpClientEngineConfig.kt

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,12 @@ public interface HttpClientEngineConfig {
6565
*/
6666
public val connectionIdleTimeout: Duration
6767

68+
/**
69+
* The maximum number of requests that will be executed concurrently by an engine. Beyond this requests
70+
* will be queued waiting to be executed by the engine.
71+
*/
72+
public val maxConcurrency: UInt
73+
6874
/**
6975
* The proxy selection policy
7076
*/
@@ -132,6 +138,12 @@ public interface HttpClientEngineConfig {
132138
*/
133139
public var connectionIdleTimeout: Duration
134140

141+
/**
142+
* The maximum number of requests that will be executed concurrently by an engine. Beyond this requests
143+
* will be queued waiting to be executed by the engine.
144+
*/
145+
public var maxConcurrency: UInt
146+
135147
/**
136148
* Set the proxy selection policy to be used.
137149
*
@@ -191,6 +203,7 @@ public open class HttpClientEngineConfigImpl(builder: HttpClientEngineConfig.Bui
191203
override val connectTimeout: Duration = builder.connectTimeout
192204
override val connectionAcquireTimeout: Duration = builder.connectionAcquireTimeout
193205
override val connectionIdleTimeout: Duration = builder.connectionIdleTimeout
206+
override val maxConcurrency: UInt = builder.maxConcurrency
194207
override val proxySelector: ProxySelector = builder.proxySelector
195208
override val hostResolver: HostResolver = builder.hostResolver
196209
override val tlsContext: TlsContext = builder.tlsContext
@@ -203,6 +216,7 @@ public open class HttpClientEngineConfigImpl(builder: HttpClientEngineConfig.Bui
203216
connectTimeout = this@HttpClientEngineConfigImpl.connectTimeout
204217
connectionAcquireTimeout = this@HttpClientEngineConfigImpl.connectionAcquireTimeout
205218
connectionIdleTimeout = this@HttpClientEngineConfigImpl.connectionIdleTimeout
219+
maxConcurrency = this@HttpClientEngineConfigImpl.maxConcurrency
206220
proxySelector = this@HttpClientEngineConfigImpl.proxySelector
207221
hostResolver = this@HttpClientEngineConfigImpl.hostResolver
208222
tlsContext = this@HttpClientEngineConfigImpl.tlsContext
@@ -213,10 +227,11 @@ public open class HttpClientEngineConfigImpl(builder: HttpClientEngineConfig.Bui
213227
public open class BuilderImpl : HttpClientEngineConfig.Builder {
214228
override var socketReadTimeout: Duration = 30.seconds
215229
override var socketWriteTimeout: Duration = 30.seconds
216-
override var maxConnections: UInt = 16u
230+
override var maxConnections: UInt = 64u
217231
override var connectTimeout: Duration = 2.seconds
218232
override var connectionAcquireTimeout: Duration = 10.seconds
219233
override var connectionIdleTimeout: Duration = 60.seconds
234+
override var maxConcurrency: UInt = 128u
220235
override var proxySelector: ProxySelector = EnvironmentProxySelector()
221236
override var hostResolver: HostResolver = HostResolver.Default
222237
override var tlsContext: TlsContext = TlsContext.Default

0 commit comments

Comments
 (0)