Skip to content

Updated connection lifecycle behavior. #1055

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Feb 4, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changes/next-release/feature-AWSSDKforJavav2-dbf32f0.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"category": "AWS SDK for Java v2",
"type": "feature",
"description": "Add support for `connectionTimeToLive`, `connectionMaxIdleTime` and `useIdleConnectionReaper` to the netty HTTP client."
}
5 changes: 5 additions & 0 deletions .changes/next-release/feature-AWSSDKforJavav2-f81a93c.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"category": "AWS SDK for Java v2",
"type": "feature",
"description": "Enable `useIdleConnectionReaper` by default for Netty and Apache."
}
6 changes: 3 additions & 3 deletions docs/LaunchChangelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -219,12 +219,12 @@ DynamoDbAsyncClient client =
| Max Connections | `clientConfig.setMaxConnections(...)`<br />`clientConfig.withMaxConnections(...)` | `httpClientBuilder.maxConnections(...)` | `httpClientBuilder.maxConcurrency(...)` |
| Connection Timeout | `clientConfig.setConnectionTimeout(...)`<br />`clientConfig.withConnectionTimeout(...)` | `httpClientBuilder.connectionTimeout(...)` | `httpClientBuilder.connectionTimeout(...)` |
| Socket Timeout | `clientConfig.setSocketTimeout(...)`<br />`clientConfig.withSocketTimeout(...)` | `httpClientBuilder.socketTimeout(...)` | `httpClientBuilder.writeTimeout(...)` <br /> `httpClientBuilder.readTimeout(...)` |
| Connection TTL | `clientConfig.setConnectionTTL(...)`<br />`clientConfig.withConnectionTTL(...)` | `httpClientBuilder.connectionTimeToLive(...)` | [Not Supported](https://github.com/aws/aws-sdk-java-v2/issues/856) |
| Connection Max Idle | `clientConfig.setConnectionMaxIdleMillis(...)`<br />`clientConfig.withConnectionMaxIdleMillis(...)` | `httpClientBuilder.connectionMaxIdleTime(...)` | [Not Supported](https://github.com/aws/aws-sdk-java-v2/issues/856) |
| Connection TTL | `clientConfig.setConnectionTTL(...)`<br />`clientConfig.withConnectionTTL(...)` | `httpClientBuilder.connectionTimeToLive(...)` | `httpClientBuilder.connectionTimeToLive(...)` |
| Connection Max Idle | `clientConfig.setConnectionMaxIdleMillis(...)`<br />`clientConfig.withConnectionMaxIdleMillis(...)` | `httpClientBuilder.connectionMaxIdleTime(...)` | `httpClientBuilder.connectionMaxIdleTime(...)` |
| Validate After Inactivity | `clientConfig.setValidateAfterInactivityMillis(...)`<br />`clientConfig.withValidateAfterInactivityMillis(...)` | Not Supported ([Request Feature](https://github.com/aws/aws-sdk-java-v2/issues/new)) | Not Supported ([Request Feature](https://github.com/aws/aws-sdk-java-v2/issues/new)) |
| Local Address | `clientConfig.setLocalAddress(...)`<br />`clientConfig.withLocalAddress(...)` | `httpClientBuilder.localAddress(...)` | [Not Supported](https://github.com/aws/aws-sdk-java-v2/issues/857) |
| Expect-Continue Enabled | `clientConfig.setUseExpectContinue(...)`<br />`clientConfig.withUseExpectContinue(...)` | `httpClientBuilder.expectContinueEnabled(...)` | Not Supported ([Request Feature](https://github.com/aws/aws-sdk-java-v2/issues/new)) |
| Connection Reaper | `clientConfig.setUseReaper(...)`<br />`clientConfig.withReaper(...)` | `httpClientBuilder.useIdleConnectionReaper(...)` | [Not Supported](https://github.com/aws/aws-sdk-java-v2/issues/856) |
| Connection Reaper | `clientConfig.setUseReaper(...)`<br />`clientConfig.withReaper(...)` | `httpClientBuilder.useIdleConnectionReaper(...)` | `httpClientBuilder.useIdleConnectionReaper(...)` |
| | `AmazonDynamoDBClientBuilder.standard()`<br />`.withClientConfiguration(clientConfiguration)`<br />`.build()` | `DynamoDbClient.builder()`<br />`.httpClientBuilder(httpClientBuilder)`<br />`.build()` | `DynamoDbAsyncClient.builder()`<br />`.httpClientBuilder(httpClientBuilder)`<br />`.build()` |


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,19 @@ public final class SdkHttpConfigurationOption<T> extends AttributeMap.Key<T> {
public static final SdkHttpConfigurationOption<Duration> CONNECTION_ACQUIRE_TIMEOUT =
new SdkHttpConfigurationOption<>("ConnectionAcquireTimeout", Duration.class);

/**
* Timeout after which an idle connection should be closed.
*/
public static final SdkHttpConfigurationOption<Duration> CONNECTION_MAX_IDLE_TIMEOUT =
new SdkHttpConfigurationOption<>("ConnectionMaxIdleTimeout", Duration.class);

/**
* Timeout after which a connection should be closed, regardless of whether it is idle. Zero indicates an infinite amount
* of time.
*/
public static final SdkHttpConfigurationOption<Duration> CONNECTION_TIME_TO_LIVE =
new SdkHttpConfigurationOption<>("ConnectionTimeToLive", Duration.class);

/**
* Maximum number of connections allowed in a connection pool.
*/
Expand All @@ -64,6 +77,7 @@ public final class SdkHttpConfigurationOption<T> extends AttributeMap.Key<T> {
*/
public static final SdkHttpConfigurationOption<Protocol> PROTOCOL =
new SdkHttpConfigurationOption<>("Protocol", Protocol.class);

/**
* Maximum number of requests allowed to wait for a connection.
*/
Expand All @@ -77,10 +91,19 @@ public final class SdkHttpConfigurationOption<T> extends AttributeMap.Key<T> {
public static final SdkHttpConfigurationOption<Boolean> TRUST_ALL_CERTIFICATES =
new SdkHttpConfigurationOption<>("TrustAllCertificates", Boolean.class);

/**
* Whether idle connection should be removed after the {@link #CONNECTION_MAX_IDLE_TIMEOUT} has passed.
*/
public static final SdkHttpConfigurationOption<Boolean> REAP_IDLE_CONNECTIONS =
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

minor, how about REAP_IDLE_CONNECTIONS_ENABLED or ENABLE_REAP_IDLE_CONNECTIONS?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was following the naming convention of TRUST_ALL_CERTIFICATES, which we can't change now. I'd rather be consistent.

new SdkHttpConfigurationOption<>("ReapIdleConnections", Boolean.class);

private static final Duration DEFAULT_SOCKET_READ_TIMEOUT = Duration.ofSeconds(30);
private static final Duration DEFAULT_SOCKET_WRITE_TIMEOUT = Duration.ofSeconds(30);
private static final Duration DEFAULT_CONNECTION_TIMEOUT = Duration.ofSeconds(2);
private static final Duration DEFAULT_CONNECTION_ACQUIRE_TIMEOUT = Duration.ofSeconds(10);
private static final Duration DEFAULT_CONNECTION_MAX_IDLE_TIMEOUT = Duration.ofSeconds(60);
private static final Duration DEFAULT_CONNECTION_TIME_TO_LIVE = Duration.ZERO;
private static final Boolean DEFAULT_REAP_IDLE_CONNECTIONS = Boolean.TRUE;
private static final int DEFAULT_MAX_CONNECTIONS = 50;
private static final int DEFAULT_MAX_CONNECTION_ACQUIRES = 10_000;
private static final Boolean DEFAULT_TRUST_ALL_CERTIFICATES = Boolean.FALSE;
Expand All @@ -93,10 +116,13 @@ public final class SdkHttpConfigurationOption<T> extends AttributeMap.Key<T> {
.put(WRITE_TIMEOUT, DEFAULT_SOCKET_WRITE_TIMEOUT)
.put(CONNECTION_TIMEOUT, DEFAULT_CONNECTION_TIMEOUT)
.put(CONNECTION_ACQUIRE_TIMEOUT, DEFAULT_CONNECTION_ACQUIRE_TIMEOUT)
.put(CONNECTION_MAX_IDLE_TIMEOUT, DEFAULT_CONNECTION_MAX_IDLE_TIMEOUT)
.put(CONNECTION_TIME_TO_LIVE, DEFAULT_CONNECTION_TIME_TO_LIVE)
.put(MAX_CONNECTIONS, DEFAULT_MAX_CONNECTIONS)
.put(MAX_PENDING_CONNECTION_ACQUIRES, DEFAULT_MAX_CONNECTION_ACQUIRES)
.put(PROTOCOL, DEFAULT_PROTOCOL)
.put(TRUST_ALL_CERTIFICATES, DEFAULT_TRUST_ALL_CERTIFICATES)
.put(REAP_IDLE_CONNECTIONS, DEFAULT_REAP_IDLE_CONNECTIONS)
.build();

private final String name;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@
import static java.util.stream.Collectors.mapping;
import static java.util.stream.Collectors.toList;
import static software.amazon.awssdk.http.SdkHttpConfigurationOption.CONNECTION_ACQUIRE_TIMEOUT;
import static software.amazon.awssdk.http.SdkHttpConfigurationOption.CONNECTION_MAX_IDLE_TIMEOUT;
import static software.amazon.awssdk.http.SdkHttpConfigurationOption.CONNECTION_TIMEOUT;
import static software.amazon.awssdk.http.SdkHttpConfigurationOption.CONNECTION_TIME_TO_LIVE;
import static software.amazon.awssdk.http.SdkHttpConfigurationOption.GLOBAL_HTTP_DEFAULTS;
import static software.amazon.awssdk.http.SdkHttpConfigurationOption.MAX_CONNECTIONS;
import static software.amazon.awssdk.http.SdkHttpConfigurationOption.READ_TIMEOUT;
Expand Down Expand Up @@ -134,7 +136,7 @@ private ConnectionManagerAwareHttpClient createClient(ApacheHttpClient.DefaultBu
builder.setRequestExecutor(new HttpRequestExecutor())
// SDK handles decompression
.disableContentCompression()
.setKeepAliveStrategy(buildKeepAliveStrategy(configuration))
.setKeepAliveStrategy(buildKeepAliveStrategy(standardOptions))
.disableRedirectHandling()
.disableAutomaticRetries()
.setUserAgent("") // SDK will set the user agent header in the pipeline. Don't let Apache waste time
Expand All @@ -144,7 +146,7 @@ private ConnectionManagerAwareHttpClient createClient(ApacheHttpClient.DefaultBu

if (useIdleConnectionReaper(configuration)) {
IdleConnectionReaper.getInstance().registerConnectionManager(
cm, connectionMaxIdleTime(configuration).toMillis());
cm, resolvedOptions.get(SdkHttpConfigurationOption.CONNECTION_MAX_IDLE_TIMEOUT).toMillis());
}

return new ApacheSdkHttpClient(builder.build(), cm);
Expand All @@ -167,16 +169,11 @@ private void addProxyConfig(HttpClientBuilder builder,
}
}

private ConnectionKeepAliveStrategy buildKeepAliveStrategy(ApacheHttpClient.DefaultBuilder configuration) {
long maxIdle = connectionMaxIdleTime(configuration).toMillis();
private ConnectionKeepAliveStrategy buildKeepAliveStrategy(AttributeMap standardOptions) {
long maxIdle = standardOptions.get(SdkHttpConfigurationOption.CONNECTION_MAX_IDLE_TIMEOUT).toMillis();
return maxIdle > 0 ? new SdkConnectionKeepAliveStrategy(maxIdle) : null;
}

private Duration connectionMaxIdleTime(DefaultBuilder configuration) {
return Optional.ofNullable(configuration.connectionMaxIdleTime)
.orElse(DefaultConfiguration.MAX_IDLE_CONNECTION_TIME);
}

private boolean useIdleConnectionReaper(DefaultBuilder configuration) {
return Boolean.TRUE.equals(configuration.useIdleConnectionReaper);
}
Expand Down Expand Up @@ -336,7 +333,7 @@ public interface Builder extends SdkHttpClient.Builder<ApacheHttpClient.Builder>
* Configure whether the idle connections in the connection pool should be closed asynchronously.
* <p>
* When enabled, connections left idling for longer than {@link #connectionMaxIdleTime(Duration)} will be
* closed. If no value is set, the default value of {@link DefaultConfiguration#MAX_IDLE_CONNECTION_TIME} is used.
* closed. This will not close connections currently in use. By default, this is enabled.
*/
Builder useIdleConnectionReaper(Boolean useConnectionReaper);
}
Expand All @@ -346,8 +343,6 @@ private static final class DefaultBuilder implements Builder {
private ProxyConfiguration proxyConfiguration = ProxyConfiguration.builder().build();
private InetAddress localAddress;
private Boolean expectContinueEnabled;
private Duration connectionTimeToLive;
private Duration connectionMaxIdleTime;
private Boolean useIdleConnectionReaper;

private DefaultBuilder() {
Expand Down Expand Up @@ -431,7 +426,7 @@ public void setExpectContinueEnabled(Boolean useExpectContinue) {

@Override
public Builder connectionTimeToLive(Duration connectionTimeToLive) {
this.connectionTimeToLive = connectionTimeToLive;
standardOptions.put(CONNECTION_TIME_TO_LIVE, connectionTimeToLive);
return this;
}

Expand All @@ -441,7 +436,7 @@ public void setConnectionTimeToLive(Duration connectionTimeToLive) {

@Override
public Builder connectionMaxIdleTime(Duration maxIdleConnectionTimeout) {
this.connectionMaxIdleTime = maxIdleConnectionTimeout;
standardOptions.put(CONNECTION_MAX_IDLE_TIMEOUT, maxIdleConnectionTimeout);
return this;
}

Expand Down Expand Up @@ -478,9 +473,7 @@ public HttpClientConnectionManager create(ApacheHttpClient.DefaultBuilder config
null,
DefaultSchemePortResolver.INSTANCE,
null,
Optional.ofNullable(configuration.connectionTimeToLive)
.orElse(DefaultConfiguration.CONNECTION_POOL_TTL)
.toMillis(),
standardOptions.get(SdkHttpConfigurationOption.CONNECTION_TIME_TO_LIVE).toMillis(),
TimeUnit.MILLISECONDS);

cm.setDefaultMaxPerRoute(standardOptions.get(SdkHttpConfigurationOption.MAX_CONNECTIONS));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,27 +15,13 @@

package software.amazon.awssdk.http.apache.internal;

import java.time.Duration;
import software.amazon.awssdk.annotations.SdkInternalApi;

/**
* Default configuration values.
*/
@SdkInternalApi
public final class DefaultConfiguration {

/**
* The default maximum idle time (in milliseconds) for a connection to be idle in the connection pool and
* still be eligible for reuse.
*/
public static final Duration MAX_IDLE_CONNECTION_TIME = Duration.ofSeconds(60);

/**
* The default expiration time for a connection in the connection pool.
* A value of -1 means infinite TTL in Apache.
*/
public static final Duration CONNECTION_POOL_TTL = Duration.ofMillis(-1);

public static final Boolean EXPECT_CONTINUE_ENABLED = Boolean.TRUE;

private DefaultConfiguration() {
Expand Down
Loading