Skip to content

Commit

Permalink
Merge pull request #354 from auth0/net-client-timeout-config
Browse files Browse the repository at this point in the history
[SDK-2550] Add networking client timeout configuration
  • Loading branch information
jimmyjames authored May 7, 2021
2 parents aa5dcb4 + 2d2d69d commit 4f851c8
Show file tree
Hide file tree
Showing 6 changed files with 123 additions and 0 deletions.
18 changes: 18 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -614,6 +614,24 @@ Requests can be executed asynchronously, using the `executeAsync()` method, whic
## API Clients Recommendations
The SDK implements a custom networking stack on top of the **OkHttp** library. The [official recommendation](https://square.github.io/okhttp/4.x/okhttp/okhttp3/-ok-http-client/#okhttpclients-should-be-shared) from Square is to re-use as much as possible these clients. However, it's not possible to pass an existing `OkHttpClient` instance to our `AuthAPI` and `ManagementAPI` clients.

The networking client used by both the `AuthAPI` and `ManagementAPI` clients can be configured through the `HttpOptions`, which enables custom timeout configuration and proxy support:

```java
HttpOptions options = new HttpOptions();

// configure timeouts; default is ten seconds for both connect and read timeouts:
options.setConnectTimeout(5);
options.setReadTimeout(15);

// configure proxy:
Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress("{IP-ADDRESS}", {PORT}));
ProxyOptions proxyOptions = new ProxyOptions(proxy);
options.setProxyOptions(proxyOptions);

// create client
AuthAPI authAPI = new AuthAPI("{CLIENT_ID}", "{CLIENT_SECRET}", options);
```

Whenever you instantiate a client, a new `OkHttpClient` instance is created internally to handle the network requests. This instance is not directly exposed for customization. In order to reduce resource consumption, make use of the _singleton pattern_ to keep a single instance of this SDK's API client during the lifecycle of your application.

For the particular case of the `ManagementAPI` client, if the token you've originally set has expired or you require to change its scopes, you can update the client's token with the `setApiToken(String)` method.
Expand Down
42 changes: 42 additions & 0 deletions src/main/java/com/auth0/client/HttpOptions.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
public class HttpOptions {

private ProxyOptions proxyOptions;
private int connectTimeout = 10;
private int readTimeout = 10;

/**
* Getter for the Proxy configuration options
Expand All @@ -24,4 +26,44 @@ public ProxyOptions getProxyOptions() {
public void setProxyOptions(ProxyOptions proxyOptions) {
this.proxyOptions = proxyOptions;
}


/**
* @return the connect timeout, in seconds
*/
public int getConnectTimeout() {
return connectTimeout;
}

/**
* Sets the value of the connect timeout, in seconds. Defaults to ten seconds. A value of zero results in no connect timeout.
* Negative numbers will be treated as zero.
* @param connectTimeout the value of the connect timeout to use.
*/
public void setConnectTimeout(int connectTimeout) {
if (connectTimeout < 0) {
connectTimeout = 0;
}
this.connectTimeout = connectTimeout;
}

/**
* @return the read timeout, in seconds
*/
public int getReadTimeout() {
return readTimeout;
}

/**
* Sets the value of the read timeout, in seconds. Defaults to ten seconds. A value of zero results in no read timeout.
* Negative numbers will be treated as zero.
*
* @param readTimeout the value of the read timeout to use.
*/
public void setReadTimeout(int readTimeout) {
if (readTimeout < 0) {
readTimeout = 0;
}
this.readTimeout = readTimeout;
}
}
3 changes: 3 additions & 0 deletions src/main/java/com/auth0/client/auth/AuthAPI.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import okhttp3.logging.HttpLoggingInterceptor.Level;

import java.io.IOException;
import java.util.concurrent.TimeUnit;

/**
* Class that provides an implementation of some of the Authentication and Authorization API methods defined in https://auth0.com/docs/api/authentication.
Expand Down Expand Up @@ -131,6 +132,8 @@ public okhttp3.Request authenticate(Route route, Response response) throws IOExc
return clientBuilder
.addInterceptor(logging)
.addInterceptor(telemetry)
.connectTimeout(options.getConnectTimeout(), TimeUnit.SECONDS)
.readTimeout(options.getReadTimeout(), TimeUnit.SECONDS)
.build();
}

Expand Down
3 changes: 3 additions & 0 deletions src/main/java/com/auth0/client/mgmt/ManagementAPI.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import okhttp3.logging.HttpLoggingInterceptor.Level;

import java.io.IOException;
import java.util.concurrent.TimeUnit;

/**
* Class that provides an implementation of the Management API methods defined in https://auth0.com/docs/api/management/v2.
Expand Down Expand Up @@ -102,6 +103,8 @@ public okhttp3.Request authenticate(Route route, Response response) throws IOExc
return clientBuilder
.addInterceptor(logging)
.addInterceptor(telemetry)
.connectTimeout(options.getConnectTimeout(), TimeUnit.SECONDS)
.readTimeout(options.getReadTimeout(), TimeUnit.SECONDS)
.build();
}

Expand Down
29 changes: 29 additions & 0 deletions src/test/java/com/auth0/client/auth/AuthAPITest.java
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,35 @@ public void shouldThrowWhenClientSecretIsNull() {
new AuthAPI(DOMAIN, CLIENT_ID, null);
}

@Test
public void shouldUseDefaultTimeValues() {
AuthAPI api = new AuthAPI(DOMAIN, CLIENT_ID, CLIENT_SECRET);
assertThat(api.getClient().connectTimeoutMillis(), is(10 * 1000));
assertThat(api.getClient().readTimeoutMillis(), is(10 * 1000));
}

@Test
public void shouldUseConfiguredTimeoutValues() {
HttpOptions options = new HttpOptions();
options.setConnectTimeout(20);
options.setReadTimeout(30);
AuthAPI api = new AuthAPI(DOMAIN, CLIENT_ID, CLIENT_SECRET, options);

assertThat(api.getClient().connectTimeoutMillis(), is(20 * 1000));
assertThat(api.getClient().readTimeoutMillis(), is(30 * 1000));
}

@Test
public void shouldUseZeroIfNegativeTimoutConfigured() {
HttpOptions options = new HttpOptions();
options.setConnectTimeout(-1);
options.setReadTimeout(-10);
AuthAPI api = new AuthAPI(DOMAIN, CLIENT_ID, CLIENT_SECRET, options);

assertThat(api.getClient().connectTimeoutMillis(), is(0));
assertThat(api.getClient().readTimeoutMillis(), is(0));
}

@Test
public void shouldNotUseProxyByDefault() throws Exception {
AuthAPI api = new AuthAPI(DOMAIN, CLIENT_ID, CLIENT_SECRET);
Expand Down
28 changes: 28 additions & 0 deletions src/test/java/com/auth0/client/mgmt/ManagementAPITest.java
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,34 @@ public void shouldUpdateApiToken() {
assertThat(api.users().apiToken, is("new token"));
}

@Test
public void shouldUseDefaultTimeoutIfNotSpecified() {
ManagementAPI api = new ManagementAPI(DOMAIN, API_TOKEN);
assertThat(api.getClient().connectTimeoutMillis(), is(10 * 1000));
assertThat(api.getClient().readTimeoutMillis(), is(10 * 1000));
}

@Test
public void shouldUseZeroIfNegativeTimeoutConfigured() {
HttpOptions options = new HttpOptions();
options.setConnectTimeout(-1);
options.setReadTimeout(-1);
ManagementAPI api = new ManagementAPI(DOMAIN, API_TOKEN, options);
assertThat(api.getClient().connectTimeoutMillis(), is(0));
assertThat(api.getClient().readTimeoutMillis(), is(0));

}

@Test
public void shouldSetTimeoutsIfConfigured() {
HttpOptions options = new HttpOptions();
options.setConnectTimeout(20);
options.setReadTimeout(30);
ManagementAPI api = new ManagementAPI(DOMAIN, API_TOKEN, options);
assertThat(api.getClient().connectTimeoutMillis(), is(20 * 1000));
assertThat(api.getClient().readTimeoutMillis(), is(30 * 1000));
}

@Test
public void shouldNotUseProxyByDefault() throws Exception {
ManagementAPI api = new ManagementAPI(DOMAIN, API_TOKEN);
Expand Down

0 comments on commit 4f851c8

Please sign in to comment.