Skip to content

Commit 15eecaf

Browse files
committed
Enable configuration of the connection timeout for AwsCrtAsyncHttpClient
1 parent 2ac6f7b commit 15eecaf

File tree

2 files changed

+102
-3
lines changed

2 files changed

+102
-3
lines changed

http-clients/aws-crt-client/src/main/java/software/amazon/awssdk/http/crt/AwsCrtAsyncHttpClient.java

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,8 @@ private AwsCrtAsyncHttpClient(DefaultBuilder builder, AttributeMap config) {
8989
.withCipherPreference(builder.cipherPreference)
9090
.withVerifyPeer(!config.get(SdkHttpConfigurationOption.TRUST_ALL_CERTIFICATES));
9191
TlsContext clientTlsContext = new TlsContext(clientTlsContextOptions)) {
92-
92+
Duration connectionTimeout = config.get(SdkHttpConfigurationOption.CONNECTION_TIMEOUT);
93+
setConnectionTimeout(clientSocketOptions, connectionTimeout);
9394
this.bootstrap = registerOwnedResource(clientBootstrap);
9495
this.socketOptions = registerOwnedResource(clientSocketOptions);
9596
this.tlsContext = registerOwnedResource(clientTlsContext);
@@ -101,6 +102,15 @@ private AwsCrtAsyncHttpClient(DefaultBuilder builder, AttributeMap config) {
101102
}
102103
}
103104

105+
private void setConnectionTimeout(SocketOptions clientSocketOptions, Duration connectionTimeout) {
106+
if (connectionTimeout == null) {
107+
return;
108+
}
109+
110+
long connectionTimeoutMillis = connectionTimeout.toMillis();
111+
clientSocketOptions.connectTimeoutMs = (int) Long.min(connectionTimeoutMillis, Integer.MAX_VALUE);
112+
}
113+
104114
private HttpMonitoringOptions revolveHttpMonitoringOptions(ConnectionHealthChecksConfiguration config) {
105115
if (config == null) {
106116
return null;
@@ -325,10 +335,10 @@ public interface Builder extends SdkAsyncHttpClient.Builder<AwsCrtAsyncHttpClien
325335
Builder connectionHealthChecksConfiguration(ConnectionHealthChecksConfiguration healthChecksConfiguration);
326336

327337
/**
328-
* A convenience method to configure the health checks for for all connections established by this client.
338+
* A convenience method to configure the health checks for all connections established by this client.
329339
*
330340
* <p>
331-
* eg: you can set a throughput threshold for the a connection to be considered healthy.
341+
* eg: you can set a throughput threshold for the connection to be considered healthy.
332342
* If the connection falls below this threshold for a configurable amount of time,
333343
* then the connection is considered unhealthy and will be shut down.
334344
*
@@ -343,6 +353,14 @@ Builder connectionHealthChecksConfiguration(Consumer<ConnectionHealthChecksConfi
343353
* Configure the maximum amount of time that a connection should be allowed to remain open while idle.
344354
*/
345355
Builder connectionMaxIdleTime(Duration connectionMaxIdleTime);
356+
357+
/**
358+
* The amount of time to wait when initially establishing a connection before giving up and timing out. The maximum
359+
* possible value, in ms, is the value of {@link Integer#MAX_VALUE}, any longer duration will be reduced to the maximum
360+
* possible value. If not specified, the connection timeout duration will be set to value defined in
361+
* {@link SdkHttpConfigurationOption#GLOBAL_HTTP_DEFAULTS}.
362+
*/
363+
Builder connectionTimeout(Duration connectionTimeout);
346364
}
347365

348366
/**
@@ -427,5 +445,11 @@ public Builder proxyConfiguration(Consumer<ProxyConfiguration.Builder> proxyConf
427445
proxyConfigurationBuilderConsumer.accept(builder);
428446
return proxyConfiguration(builder.build());
429447
}
448+
449+
@Override
450+
public Builder connectionTimeout(Duration connectionTimeout) {
451+
standardOptions.put(SdkHttpConfigurationOption.CONNECTION_TIMEOUT, connectionTimeout);
452+
return this;
453+
}
430454
}
431455
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
/*
2+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License").
5+
* You may not use this file except in compliance with the License.
6+
* A copy of the License is located at
7+
*
8+
* http://aws.amazon.com/apache2.0
9+
*
10+
* or in the "license" file accompanying this file. This file is distributed
11+
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12+
* express or implied. See the License for the specific language governing
13+
* permissions and limitations under the License.
14+
*/
15+
16+
package software.amazon.awssdk.http.crt;
17+
18+
import static org.assertj.core.api.Assertions.assertThat;
19+
import static org.junit.jupiter.params.provider.Arguments.arguments;
20+
import static org.testng.Assert.fail;
21+
22+
import java.lang.reflect.Field;
23+
import java.time.Duration;
24+
import java.util.stream.Stream;
25+
import org.junit.jupiter.api.Test;
26+
import org.junit.jupiter.api.extension.ExtensionContext;
27+
import org.junit.jupiter.params.ParameterizedTest;
28+
import org.junit.jupiter.params.provider.Arguments;
29+
import org.junit.jupiter.params.provider.ArgumentsProvider;
30+
import org.junit.jupiter.params.provider.ArgumentsSource;
31+
import org.junit.platform.commons.support.ReflectionSupport;
32+
import software.amazon.awssdk.crt.io.SocketOptions;
33+
import software.amazon.awssdk.http.SdkHttpConfigurationOption;
34+
import software.amazon.awssdk.http.async.SdkAsyncHttpClient;
35+
36+
class AwsCrtHttpClientBuilderTest {
37+
38+
@ParameterizedTest
39+
@ArgumentsSource(TimeoutArgumentProvider.class)
40+
void createBuilder_withConnectionTimeout_updateClientTimeout(Duration timeout, int millis) throws Exception {
41+
SdkAsyncHttpClient client = AwsCrtAsyncHttpClient.builder().connectionTimeout(timeout).build();
42+
validateTimeoutValue(client, millis);
43+
client.close();
44+
}
45+
46+
@Test
47+
void createBuilder_withoutConnectionTimeout_shouldUseDefaultValue() throws Exception {
48+
SdkAsyncHttpClient client = AwsCrtAsyncHttpClient.create();
49+
int globalDefaultConnectionTimeout =
50+
(int) SdkHttpConfigurationOption.GLOBAL_HTTP_DEFAULTS.get(SdkHttpConfigurationOption.CONNECTION_TIMEOUT).toMillis();
51+
validateTimeoutValue(client, globalDefaultConnectionTimeout);
52+
client.close();
53+
}
54+
55+
private void validateTimeoutValue(SdkAsyncHttpClient client, int expected) throws Exception {
56+
Field socketOptionsField = AwsCrtAsyncHttpClient.class.getDeclaredField("socketOptions");
57+
SocketOptions options = (SocketOptions) ReflectionSupport.tryToReadFieldValue(socketOptionsField, client)
58+
.ifFailure(e -> fail("Cannot read field socketOptions from class "
59+
+ "AwsCrtAsyncHttpClient", e))
60+
.get();
61+
assertThat(options.connectTimeoutMs).isEqualTo(expected);
62+
}
63+
64+
private static class TimeoutArgumentProvider implements ArgumentsProvider {
65+
@Override
66+
public Stream<? extends Arguments> provideArguments(ExtensionContext context) {
67+
return Stream.of(
68+
arguments(Duration.ofSeconds(0), 0),
69+
arguments(Duration.ofSeconds(1), 1_000),
70+
arguments(Duration.ofSeconds(10), 10_000),
71+
arguments(Duration.ofDays(40), Integer.MAX_VALUE)
72+
);
73+
}
74+
}
75+
}

0 commit comments

Comments
 (0)