Skip to content
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 user agent info to ADT client, miscellaneous builder improvements #14237

Merged
merged 5 commits into from
Aug 19, 2020

Conversation

timtay-microsoft
Copy link
Member

@timtay-microsoft timtay-microsoft commented Aug 18, 2020

User agent looks like: "User-Agent=azsdk-java-azure-digitaltwins-core/1.0.0-beta.1 (1.8.0_201; Windows 10; 10.0)" when run from a windows 10 machine.

See inline below for my notes on the other small changes in this PR

User agent looks like: "User-Agent=azsdk-java-azure-digitaltwins-core/1.0.0-beta.1 (1.8.0_201; Windows 10; 10.0)" when run from a windows 10 machine
@@ -53,7 +54,7 @@ public DigitalTwinsServiceVersion getServiceVersion() {
// this annotation lets users know this method makes a call to the service and whether it returns a single resource or a collection of resources
@ServiceMethod(returns = ReturnType.SINGLE)
// TODO This is just a temporary implementation for test purposes. This should be spruced up/replaced once this API is actually designed
public DigitalTwinsGetByIdResponse getDigitalTwin(String digitalTwinId) {
public Response<Object> getDigitalTwin(String digitalTwinId) {
Copy link
Member Author

Choose a reason for hiding this comment

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

This works in the sync client, but not in the async client. We'll still need the java autorest team to fix their bug so that the protocol layer actually returns the expected type

Copy link
Contributor

Choose a reason for hiding this comment

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

I may have missed it but what and why does it not work for async?

// of the header's value. These null values are equivalent to just constructing "new RetryPolicy()"
private static final String retryAfterHeader = null;
private static final ChronoUnit retryAfterTimeUnit = null;
private static final RetryPolicy DEFAULT_RETRY_POLICY = new RetryPolicy(retryAfterHeader, retryAfterTimeUnit);
Copy link
Member Author

Choose a reason for hiding this comment

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

Adding these explicitly even though they are default values so that if/when we add support for retry-after headers, it is easy to figure out that the Azure Core RetryPolicy class handles that for us as long as we tell it what our service sends as the header name and time unit

Copy link
Member

Choose a reason for hiding this comment

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

Doesn't RetryPolicy have null check for these values? Does it inform the calling application that it is using default values since null was supplied, or does it silently make the switch?


private Configuration configuration;

public DigitalTwinsClientBuilder()
Copy link
Member Author

Choose a reason for hiding this comment

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

Adding a default constructor so that we don't forget it exists, and also to assign some default values

// Closest to API goes first, closest to wire goes last.
List<HttpPipelinePolicy> policies = new ArrayList<>();

String clientName = properties.getOrDefault(SDK_NAME, "UnknownName");
String clientVersion = properties.getOrDefault(SDK_VERSION, "UnknownVersion");
Copy link
Member Author

Choose a reason for hiding this comment

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

These values come from azure-digital-twins.properties file that is added in this PR

if (buildConfiguration == null)
{
buildConfiguration = Configuration.getGlobalConfiguration().clone();
}
Copy link
Member Author

Choose a reason for hiding this comment

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

In the configurations client code, their builder never overwrites the values of the instance variables in the builder. Instead it creates local copies that can be altered instead

Copy link
Member

Choose a reason for hiding this comment

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

Do we know why? Is this more efficient, or is it the defined process?

@@ -0,0 +1,2 @@
name=${project.artifactId}
version=${project.version}
Copy link
Member Author

Choose a reason for hiding this comment

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

"azure-digitaltwins-core" and "1.0.0-beta.1" as defined in the pom file right now


private final Map<String, String> properties;

private Configuration configuration;
Copy link
Member Author

Choose a reason for hiding this comment

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

Used for user agent string, and other functionality. See here

// This is the name of the properties file in this repo that contains the default properties
private static final String DIGITAL_TWINS_PROPERTIES = "azure-digital-twins.properties";

// These are the keys to the above properties file that define the sdk's name and version for use in the user agent string
Copy link
Member

Choose a reason for hiding this comment

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

Call it 'client library'. I have heard that feedback from the SDK architects.

}

return new DigitalTwinsAsyncClient(this.httpPipeline, this.serviceVersion, this.endpoint);
return new DigitalTwinsAsyncClient(this.httpPipeline, serviceVersion, this.endpoint);
Copy link
Member

Choose a reason for hiding this comment

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

I'm not a java expert but why was 'this' removed?

Copy link
Member Author

Choose a reason for hiding this comment

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

In this case, removing the "this." means that I wanted to use the locally defined variable here instead of the instance variable. I've seen this pattern in the builders in track 2 where you don't assign the default value to the instance variables when building the pipeline. Instead, you create a local variable and assign its value to the default if the user never set the instance variable's value

@timtay-microsoft timtay-microsoft merged commit 63b2889 into master Aug 19, 2020
@timtay-microsoft timtay-microsoft deleted the feature/adt/timtay/userAgent branch August 19, 2020 18:19
// Adds a "x-ms-client-request-id" header to each request. This header is useful for tracing requests through Azure ecosystems
policies.add(new RequestIdPolicy());

// Only the RequestIdPolicy will take effect prior to the retry policy
// Only the RequestIdPolicy and UserAgentPolicy will take effect prior to the retry policy since neither of those need
// to change in any way upon retry
Copy link
Member

Choose a reason for hiding this comment

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

👍

// Custom policies, authentication policy, and add date policy all take place after the retry policy
// Custom policies, authentication policy, and add date policy all take place after the retry policy which means
// they will be applied once per retry. For instance, the AddDatePolicy will add a different date time header
// each time the retry is attempted.
Copy link
Member

Choose a reason for hiding this comment

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

Q - do we know if AddDatePolicy updates the date per retry attempt, or it updates the date for each http request made?

Copy link
Member Author

Choose a reason for hiding this comment

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

Since that policy is applied after the retry policy, each retry message will have a date time header that fits when the retry attempt occurred

Copy link
Member

Choose a reason for hiding this comment

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

I am not sure if I understand this correctly:

  1. A client is created, date policy is set.
  2. Make http request (1) with this client -> current date is added to the request - request is a success.
  3. Make http request (2) with this client -> current date is added to the request - request fails -> retry kicks in -> new http request (3) is made.

Since the current date is sent with request (1), (2) and (3), how does retry matter here?
Or am I missing something?

For auth, I can understand, that the next time retrt happens, you also want the auth credentials to be refreshed; but I cannot understand why date policy is relevant with retry.

Copy link
Member Author

Choose a reason for hiding this comment

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

We discussed this offline, and I'm putting up another PR to address my confusing wording of this #14283

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