Skip to content

Endpoint Discovery for DynamoDb #853

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
Jan 17, 2019
Merged

Endpoint Discovery for DynamoDb #853

merged 2 commits into from
Jan 17, 2019

Conversation

spfink
Copy link
Contributor

@spfink spfink commented Nov 20, 2018

Supports the endpoint discovery spec for DynamoDb.

URI cachedEndpoint = endpointDiscoveryCache.get(key,
testDiscoveryIdentifiersRequiredRequest.endpointDiscoveryRequest(),
clientConfiguration.option(SdkClientOption.ENDPOINT));
clientConfiguration.copy(o -> o.option(SdkClientOption.ENDPOINT, cachedEndpoint));
Copy link
Contributor

Choose a reason for hiding this comment

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

This doesn't change the original configuration. Also we don't want to update the client endpoint right as the new computed endpoint is only valid for that operation.

For endpoint trait, I am passing the hostPrefix to CientExecutionParams and modifying the endpoint in BaseClientHandler. But this is causing issues with path as its being modified multiple times. I am thinking of passing the hostprefix to marshallers and resolve the endpoint there before creating the HttpFullRequest.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ah, yes, was on a different version when I was doing this. Will update.

HttpResponseHandler<AwsServiceException> errorResponseHandler = createErrorResponseHandler(protocolFactory,
operationMetadata);

String key = clientConfiguration.option(AwsClientOption.CREDENTIALS_PROVIDER).resolveCredentials().accessKeyId();
Copy link
Contributor

Choose a reason for hiding this comment

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

Would this not take into account request level credentials?

Copy link
Contributor

Choose a reason for hiding this comment

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

Have same question

operationMetadata);

String key = clientConfiguration.option(AwsClientOption.CREDENTIALS_PROVIDER).resolveCredentials().accessKeyId();
URI cachedEndpoint = endpointDiscoveryCache.get(key,
Copy link
Contributor

Choose a reason for hiding this comment

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

This cachedEndpoint doesn't appear to be used. Also for async this seems like it would be kind of blocking, at least for the first call.

Copy link
Contributor

Choose a reason for hiding this comment

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

It would only be blocking if endpoint discovery is set as required. Otherwise we use the default endpoint. Is that correct?

@@ -33,6 +33,11 @@
<artifactId>auth</artifactId>
<version>${awsjavasdk.version}</version>
</dependency>
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>profiles</artifactId>
Copy link
Contributor

Choose a reason for hiding this comment

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

Why do we need this dependency?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

You can enable endpoint discovery through the profile file so I have a provider for it that requires the profiles module.

import software.amazon.awssdk.annotations.SdkInternalApi;

@SdkInternalApi
public class EndpointDiscoveryEndpoint {
Copy link
Contributor

Choose a reason for hiding this comment

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

Final

return builder().endpoint(endpoint).expirationTime(expirationTime);
}

public interface Builder {
Copy link
Contributor

Choose a reason for hiding this comment

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

Should these extend any of that SdkBuilder copyable builder stuff?

}
}

if (endpoint.expirationTime().isBefore(Instant.now())) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Does this mean it's already expired? If so are we returning the expired endpoint to the customer? Should we attempt to refresh it before it expires?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Expired endpoints can be used until a 421 status code or InvalidEndpointException is thrown.

Once an endpoint is expired, we extend the expiration to 60 seconds and immediately attempt a refresh. We extend the expiration 60 seconds so that we aren't refreshing every time.

Copy link
Contributor

Choose a reason for hiding this comment

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

Hmm gotcha. So expired means will become invalid soon?

return operationName;
}

public Optional<Map<String, String>> identifiers() {
Copy link
Contributor

Choose a reason for hiding this comment

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

Should we copy and make this map unmodifiable in constructor?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We certainly could but not sure if we need to given this is an internal use only class.

@SdkInternalApi
public interface EndpointDiscoveryProvider {

boolean resolveEndpointDiscovery();
Copy link
Contributor

Choose a reason for hiding this comment

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

Can you add some docs here? I'm not sure what boolean is supposed to represent, I guess if endpoint discovery is enabled?

import software.amazon.awssdk.codegen.poet.PoetExtensions;
import software.amazon.awssdk.codegen.poet.PoetUtils;

public class EndpointDiscoveryCacheLoaderGenerator implements ClassSpec {
Copy link
Contributor

Choose a reason for hiding this comment

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

Can you add some code gen tests for this thing?

@@ -366,6 +372,15 @@ private MethodSpec getValueForField() {
return methodBuilder.build();
}

private MethodSpec endpointDiscoveryRequest() {
Copy link
Contributor

Choose a reason for hiding this comment

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

Do we need to put this on the service model? Seems like an odd place for it.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Any alternative suggestions?

If not on the generated models for the requests, we'd have to either generate a separate class per request or generate a list of which fields need to be pulled out for the identifiers for each request.

Copy link
Contributor

Choose a reason for hiding this comment

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

This method is only called in the client. So what do you think about generating in the client method impl?

Code in cilent will change from

        endpointDiscoveryCache.get(key,
                                   listBackupsRequest.endpointDiscoveryRequest(),
                                   clientConfiguration.option(SdkClientOption.ENDPOINT));

to

        endpointDiscoveryCache.get(key,
                                   EndpointDiscoveryRequest.builder().required(false).build(),
                                   clientConfiguration.option(SdkClientOption.ENDPOINT));

@codecov-io
Copy link

codecov-io commented Jan 4, 2019

Codecov Report

Merging #853 into master will decrease coverage by 0.02%.
The diff coverage is 52.67%.

Impacted file tree graph

@@             Coverage Diff              @@
##             master     #853      +/-   ##
============================================
- Coverage     55.61%   55.58%   -0.03%     
- Complexity     4510     4566      +56     
============================================
  Files           799      810      +11     
  Lines         27487    27813     +326     
  Branches       2222     2241      +19     
============================================
+ Hits          15286    15461     +175     
- Misses        11488    11638     +150     
- Partials        713      714       +1
Impacted Files Coverage Δ Complexity Δ
...oviders/DefaultEndpointDiscoveryProviderChain.java 0% <0%> (ø) 0 <0> (?)
...dpointdiscovery/EndpointDiscoveryRefreshCache.java 0% <0%> (ø) 0 <0> (?)
...very/providers/EndpointDiscoveryProviderChain.java 0% <0%> (ø) 0 <0> (?)
...egen/emitters/tasks/AsyncClientGeneratorTasks.java 0% <0%> (ø) 0 <0> (ø) ⬇️
...degen/emitters/tasks/SyncClientGeneratorTasks.java 0% <0%> (ø) 0 <0> (ø) ⬇️
...ndpointdiscovery/EndpointDiscoveryCacheLoader.java 0% <0%> (ø) 0 <0> (?)
...e/endpointdiscovery/EndpointDiscoveryEndpoint.java 0% <0%> (ø) 0 <0> (?)
...ers/SystemPropertiesEndpointDiscoveryProvider.java 0% <0%> (ø) 0 <0> (?)
...ry/providers/ProfileEndpointDiscoveryProvider.java 0% <0%> (ø) 0 <0> (?)
...degen/poet/builder/BaseClientBuilderInterface.java 83.33% <0%> (-13.89%) 6 <0> (ø)
... and 50 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update a58b325...78cc403. Read the comment docs.


for (OperationModel o : operations.values()) {
if (o.isEndpointOperation()) {
endpointOperation = o;
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit: we can break after finding the operation.

@@ -366,6 +372,15 @@ private MethodSpec getValueForField() {
return methodBuilder.build();
}

private MethodSpec endpointDiscoveryRequest() {
Copy link
Contributor

Choose a reason for hiding this comment

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

This method is only called in the client. So what do you think about generating in the client method impl?

Code in cilent will change from

        endpointDiscoveryCache.get(key,
                                   listBackupsRequest.endpointDiscoveryRequest(),
                                   clientConfiguration.option(SdkClientOption.ENDPOINT));

to

        endpointDiscoveryCache.get(key,
                                   EndpointDiscoveryRequest.builder().required(false).build(),
                                   clientConfiguration.option(SdkClientOption.ENDPOINT));

operationMetadata);

String key = clientConfiguration.option(AwsClientOption.CREDENTIALS_PROVIDER).resolveCredentials().accessKeyId();
URI cachedEndpoint = endpointDiscoveryCache.get(key,
Copy link
Contributor

Choose a reason for hiding this comment

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

It would only be blocking if endpoint discovery is set as required. Otherwise we use the default endpoint. Is that correct?

HttpResponseHandler<AwsServiceException> errorResponseHandler = createErrorResponseHandler(protocolFactory,
operationMetadata);

String key = clientConfiguration.option(AwsClientOption.CREDENTIALS_PROVIDER).resolveCredentials().accessKeyId();
Copy link
Contributor

Choose a reason for hiding this comment

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

Have same question

if (endpoint.expirationTime().isBefore(Instant.now())) {
cache.put(key, endpoint.toBuilder().expirationTime(Instant.now().plusSeconds(60)).build());
String finalKey = key;
discoverEndpoint(null).thenApply(v -> cache.put(finalKey, v));
Copy link
Contributor

Choose a reason for hiding this comment

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

Is passing null request to discoverEndpoint method right?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Changed to the request object.

return new BuilderImpl(this);
}

public interface Builder extends CopyableBuilder<Builder, EndpointDiscoveryRequest> {
Copy link
Contributor

Choose a reason for hiding this comment

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

Add docs?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Will add.

@spfink
Copy link
Contributor Author

spfink commented Jan 11, 2019

@varunnvs92, can't reply to some of your comments for some reason.

In the async client, it would only be blocking if endpoint discovery is required. Otherwise, it will be non-blocking.

Copy link
Contributor

@varunnvs92 varunnvs92 left a comment

Choose a reason for hiding this comment

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

LGTM

@spfink spfink force-pushed the finks/endpoint-discovery branch from 17d093b to 78cc403 Compare January 17, 2019 03:57
@spfink spfink merged commit 938a73b into master Jan 17, 2019
@spfink spfink deleted the finks/endpoint-discovery branch March 17, 2020 23:41
aws-sdk-java-automation pushed a commit that referenced this pull request May 21, 2020
…e6bbd825

Pull request: release <- staging/fc650e8a-ed4f-453a-b1b1-4619e6bbd825
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants