-
Notifications
You must be signed in to change notification settings - Fork 864
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
Add the ability to configure SocketOptions on the AwsCrtAsyncHttpClient #3457
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM!, someone from the Java SDK team could you have a look?
...aws-crt-client/src/main/java/software/amazon/awssdk/http/crt/SocketOptionsConfiguration.java
Outdated
Show resolved
Hide resolved
...aws-crt-client/src/main/java/software/amazon/awssdk/http/crt/SocketOptionsConfiguration.java
Outdated
Show resolved
Hide resolved
...ents/aws-crt-client/src/main/java/software/amazon/awssdk/http/crt/AwsCrtAsyncHttpClient.java
Outdated
Show resolved
Hide resolved
private int connectTimeoutMs = 3000; | ||
private int keepAliveIntervalSecs = 0; | ||
private int keepAliveTimeoutSecs = 0; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of defining defaults here, I think we should put the configured values into the standard options map like below. The SDK will use the global defaults automatically for any options that are not configured
Lines 542 to 545 in b1f8989
public Builder connectionTimeout(Duration timeout) { | |
Validate.isPositive(timeout, "connectionTimeout"); | |
standardOptions.put(SdkHttpConfigurationOption.CONNECTION_TIMEOUT, timeout); | |
return this; |
Lines 155 to 171 in b1f8989
public static final AttributeMap GLOBAL_HTTP_DEFAULTS = AttributeMap | |
.builder() | |
.put(READ_TIMEOUT, DEFAULT_SOCKET_READ_TIMEOUT) | |
.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) | |
.put(TCP_KEEPALIVE, DEFAULT_TCP_KEEPALIVE) | |
.put(TLS_KEY_MANAGERS_PROVIDER, DEFAULT_TLS_KEY_MANAGERS_PROVIDER) | |
.put(TLS_TRUST_MANAGERS_PROVIDER, DEFAULT_TLS_TRUST_MANAGERS_PROVIDER) | |
.put(TLS_NEGOTIATION_TIMEOUT, DEFAULT_TLS_NEGOTIATION_TIMEOUT) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can move those there, sure.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Based on the discussion in #3457 (comment), i think it doesn't make sense to list defaults for these
* @param domain socket domain | ||
* @return Builder | ||
*/ | ||
Builder domain(SocketOptions.SocketDomain domain); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we need domain
and type
? If I understand correctly, there's no use-case for configuring these two with AWS services, right? We can always add them in the future if needed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
They probably need to be kept for later http/3, and other alternative transports, but yes assuming this is for building an http client, it's currently always TCP
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I ended up keeping them for the advanced users, since it's all going to the same place in the CRT, but decoupled from both connection timeouts, and the keep-alive configuration so that SDK users discovering this can get their iteratively
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IMO we should only expose public APIs if needed to keep it a 2-way door because it'd be a lot harder to remove/change them in the future.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are you saying I should remove SocketOptionsConfiguration
from this change so we can decide later how to expose them? I'm fine with that
Builder keepAliveIntervalSecs(int keepAliveIntervalSecs); | ||
|
||
/** | ||
* Sets the number of seconds to wait for a keepalive response before considering the connection timed out | ||
* @param keepAliveTimeoutSecs number of seconds to wait for a keepalive response before considering the connection timed out | ||
* @return Builder | ||
*/ | ||
Builder keepAliveTimeoutSecs(int keepAliveTimeoutSecs); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we expect customers to configure keepAliveIntervalSecs
and keepAliveTimeoutSecs
? If not, should we just introduce tcpKeepAlive(Boolean tcpKeepAlive)
and pass default values defined in the SDK to CRT? Because exposing too many knobs may make the SDK more complex to use.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will default to your judgement there. I suspect just being able to enable keepAlive should be enough.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
no, keep alive is worthless without setting those values. The kernel defaults are never what anyone needs for these use-cases. So, it needs to be here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My concern is that these settings may be too "advanced", so some customers may just set some random values w/o doing any research. I'm fine with adding these two, but I think we should still introduce a boolean tcpKeepAlive and define some "safe" defaults for tcpInterval and tcpKeepAliveIntervalSecs if they are not configured. WDYT?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IMO I think the right way to do this would be to separate KeepAliveConfiguration into a dedicated object.
If it's not set, that means customers want the default, disabled. If they DO set it, then they should be setting both the interval and the timeout, and they're "opting-in" to knowing what they're doing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's either add these values or don't bother. The kernel defaults will not meet anyone's needs. It's on the scale of hours before the first probe gets sent. It IS too advanced, but the answer isn't to do it for the user. By the time you're tuning keep alive, both of these values need to be a conscious decision by the user.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@nikp I think a separate class is fine. Can we name it TcpKeepAliveConfiguration
though? because people may confuse it with HTTP keep alive (we've had customers asking for clarification before)
@JonathanHenson I think that's fair. We'd probably need to provide some guidance on how to tune them.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm gonna submit a new revision with that approach - I think it'll work nicely :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I submitted TcpKeepAliveConfiguration, please take a look @zoewangg
OK I think I can address the requested comments but there are 3 questions for @zoewangg in my mind that are not clear and worth leaving a record of for future extension.
|
I think they should be top-level fields. To be clear, we are going to just add
I think this should be fine. CRT HTTP Client is still in Developer Preview, so breaking change is expected
They should not share a common interface actually. It's by design because not every HTTP client supports the same client options. |
Maybe, I'm starting to second-guess it. Your reference to NettyNioAsyncHttpClient having a boolean field made me think that we already have configured defaults somewhere for keepAliveInterval and keepAliveTimeout but we do not - actually it looks like https://github.com/aws/aws-sdk-java-v2/blob/master/http-clients/netty-nio-client/src/main/java/software/amazon/awssdk/http/nio/netty/NettyNioAsyncHttpClient.java lets Which means that we either need to add sensible defaults for those values, or we let customers configure them. Since a sensible keep-alive interval very much depends on the underlying connection handler and their timeouts, I think it makes more sense to let customers configure them. Which creates weird validation edge-cases. Would it be better to just have the 2 Duration fields and if they're not set we treat it as tcpKeepAlive=false, and if they're set, true?
That's fine, but we should be explicit. We can't change the defaults for the underlying
An exercise for a future reader then. |
Yes, we do not have defaults for keepAliveInterval and keepAliveTimeout because the existing HTTP clients don't support them.
It it forwarded to the client through Line 104 in e547f1f
Line 57 in e547f1f
Yes, it's used by all HTTP clients that support connect timeout, i.e., Netty and Apache HTTP client.
I'd vote for adding sensible defaults and keeping tcpKeepAlive. Moved this conversion to #3457 (comment) |
We could define an CRT HTTP defaults attribute map that has connect timeout of 3 seconds and merge the map in the build method. Example in netty: Lines 77 to 80 in e547f1f
Lines 726 to 730 in e547f1f
|
3f0ec56
to
1f8981e
Compare
Submitted new revision:
|
...ents/aws-crt-client/src/main/java/software/amazon/awssdk/http/crt/AwsCrtAsyncHttpClient.java
Outdated
Show resolved
Hide resolved
OK I've removed SocketOptionsConfiguration to leave that for a future change, and applied the rest of the feedback. |
...ents/aws-crt-client/src/main/java/software/amazon/awssdk/http/crt/AwsCrtAsyncHttpClient.java
Show resolved
Hide resolved
...ents/aws-crt-client/src/main/java/software/amazon/awssdk/http/crt/AwsCrtAsyncHttpClient.java
Outdated
Show resolved
Hide resolved
5afb2ee
to
252993f
Compare
LGTM. Running the builds now |
@nikp looks like there are some checkstyle errors. We can also take it over here if that works better
You can try locally using the following commands:
|
7533fee
to
9d25519
Compare
… and advanced SocketOptions on the AwsCrtAsyncHttpClient. This is necessary for any clients with long-running connections that exceed default socket timeouts of services along the call path, and need to enable keep-alive settings which the CRT client supports, but the Java client wasn't exposing to callers
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for your contribution!
SonarCloud Quality Gate failed. |
Motivation and Context
This is necessary for any clients with long-running connections that exceed default socket timeouts of services along the call path, and need to enable keep-alive settings which the CRT client supports, but the Java client wasn't exposing to callers
Modifications
Adds a new configuration parameter object to encapsulate SocketOptions to the AwsCrtAsyncHttpClient DefaultBuilder
Testing
Unit testing - the change is very isolated from the rest of the package
Screenshots (if appropriate)
Types of changes
Checklist
mvn install
succeedsmvn install
does not succeed due to[ERROR] Failed to execute goal org.apache.maven.plugins:maven-shade-plugin:3.1.0:shade (default) on project third-party-jackson-core: Error creating shaded jar: duplicate entry: META-INF/services/software.amazon.awssdk.thirdparty.jackson.core.JsonFactory
, however the code I added is independent and I verified that the new code unit tests passscripts/new-change
script and following the instructions. Commit the new file created by the script in.changes/next-release
with your changes.^ I'm actually not sure about the last one - @JonathanHenson guided us to this change but I do see the LaunchChangelog references TCP Keep-Alive. Is it related?
License