Skip to content

Commit

Permalink
feat: configurable request timeouts (#478)
Browse files Browse the repository at this point in the history
* chore: bumped Gradle version

* feat: Configurable request timeouts

* chore: update GitHub workflow permissions

* Bump version: v7.7.0 → v7.8.0

* docs: update README

* fix: flaky timeout test
  • Loading branch information
SMadani authored Sep 7, 2023
1 parent 2e07f7d commit a6fb1a8
Show file tree
Hide file tree
Showing 15 changed files with 233 additions and 103 deletions.
2 changes: 1 addition & 1 deletion .bumpversion.cfg
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[bumpversion]
commit = True
tag = False
current_version = v7.7.0
current_version = v7.8.0
parse = (?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)(\-(?P<release>[a-z]+)(?P<build>\d+))?
serialize =
{major}.{minor}.{patch}-{release}{build}
Expand Down
13 changes: 13 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,19 @@ on:
- main
pull_request:

permissions:
actions: write
checks: write
contents: read
deployments: read
issues: write
discussions: write
packages: none
pages: write
pull-requests: write
security-events: write
statuses: write

jobs:
build:
runs-on: ${{ matrix.os }}
Expand Down
14 changes: 14 additions & 0 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,20 @@ name: Publish to Nexus
on:
release:
types: [published]

permissions:
actions: write
checks: write
contents: write
deployments: read
issues: write
discussions: write
packages: write
pages: write
pull-requests: write
security-events: write
statuses: write

jobs:
build:
runs-on: ubuntu-latest
Expand Down
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/)
and this project adheres to [Semantic Versioning](http://semver.org/).

# [7.8.0] - 2023-09-07
- Added capability to configure request timeouts (default is 60 seconds)
- Deprecated custom HTTP client implementation setting
- Internal refactoring of Numbers, Conversion and Number Insight implementations

# [7.7.0] - 2023-08-10
- Added Users API implementation
- Major refactoring of how endpoints are implemented internally
Expand Down
60 changes: 29 additions & 31 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,9 @@ See all of our SDKs and integrations on the [Vonage Developer portal](https://de

## Installation

Releases are published to [Maven Central](https://central.sonatype.com/artifact/com.vonage/client/7.7.0/snippets).
Releases are published to [Maven Central](https://central.sonatype.com/artifact/com.vonage/client/7.8.0/snippets).
Instructions for your build system can be found in the snippets section.
They're also available from [here](https://mvnrepository.com/artifact/com.vonage/client/7.7.0).
They're also available from [here](https://mvnrepository.com/artifact/com.vonage/client/7.8.0).
Release notes can be found in the [changelog](CHANGELOG.md).

### Build It Yourself
Expand Down Expand Up @@ -85,65 +85,63 @@ to your project's classpath.

## Configuration

### Customize the Base URI
By default, the client will use https://api.nexmo.com, https://rest.nexmo.com, https://sns.nexmo.com and https://api-eu.vonage.com as base URIs for the various endpoints. To customize these you can instantiate `VonageClient` with an `HttpConfig` object.

`HttpConfig.Builder` has been created to assist in building this object. Usage is as follows:
## Typical Instantiation
For default configuration, you just need to specify your Vonage account credentials using API key and secret, private
key and application ID or both. For maximum compatibility with all APIs, it is recommended that you specify both
authentication methods, like so:

```java
HttpConfig httpConfig = HttpConfig.builder()
.apiBaseUri("https://api.example.com")
.restBaseUri("https://rest.example.com")
.snsBaseUri("https://sns.example.com")
.apiEuBaseUri("https://api-eu.example.com")
.build();

VonageClient client = VonageClient.builder()
.applicationId(APPLICATION_ID)
.privateKeyPath(PRIVATE_KEY_PATH)
.apiKey(API_KEY)
.apiSecret(API_SECRET)
.httpConfig(httpConfig)
.build();
```

If you do not specify a property, it will take on whatever the default value is. You can also set all three with a single method:
### Customize the Base URI
By default, the client will use https://api.nexmo.com, https://rest.nexmo.com, https://sns.nexmo.com and https://api-eu.vonage.com as base URIs for the various endpoints. To customize these you can instantiate `VonageClient` with an `HttpConfig` object.

`HttpConfig.Builder` has been created to assist in building this object. Usage is as follows:

```java
HttpConfig httpConfig = HttpConfig.builder().baseUri("http://example.com").build();
HttpConfig httpConfig = HttpConfig.builder()
.apiBaseUri("https://api.example.com")
.restBaseUri("https://rest.example.com")
.snsBaseUri("https://sns.example.com")
.apiEuBaseUri("https://api-eu.example.com")
.build();

VonageClient client = VonageClient.builder()
.apiKey(API_KEY)
.apiSecret(API_SECRET)
.apiKey(API_KEY).apiSecret(API_SECRET)
.httpConfig(httpConfig)
.build();
```

To keep the default values, you can use `HttpConfig.defaultConfig()`:
If you do not specify a property, it will take on whatever the default value is. You can also set all three with a single method:

```java
HttpConfig httpConfig = HttpConfig.defaultConfig();
HttpConfig httpConfig = HttpConfig.builder().baseUri("http://example.com").build();

VonageClient client = VonageClient.builder()
.apiKey(API_KEY)
.apiSecret(API_SECRET)
.apiKey(API_KEY).apiSecret(API_SECRET)
.httpConfig(httpConfig)
.build();
```

You can also instantiate without the parameter:
### Custom Timeout

By default, the SDK has a 1-minute timeout for requests.
You can change this to be longer or shorter using `HttpConfig`. The following example sets this to 12 seconds:

```java
VonageClient client = VonageClient.builder()
.apiKey(API_KEY)
.apiSecret(API_SECRET)
.applicationId(APPLICATION_ID)
.privateKeyPath(PRIVATE_KEY_PATH)
.httpConfig(HttpConfig.builder().timeoutMillis(12_000).build())
.build();
```

### Custom HTTP Configuration

If you need to configure the Apache HttpClient used for making requests, you can
call `VonageClient.Builder.httpClient()` to supply your custom configured object. This
can be useful, for example, if you must use an HTTP proxy to make requests or to configure SSL Certificates.

## Frequently Asked Questions

**Q: What is your policy on thread safety?**
Expand Down
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ plugins {

group = "com.vonage"
archivesBaseName = "client"
version = "7.7.0"
version = "7.8.0"
sourceCompatibility = "1.8"
targetCompatibility = "1.8"

Expand Down
2 changes: 1 addition & 1 deletion gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.2.1-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-bin.zip
networkTimeout=10000
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
34 changes: 33 additions & 1 deletion src/main/java/com/vonage/client/HttpConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,29 @@ public class HttpConfig {
DEFAULT_SNS_BASE_URI = "https://sns.nexmo.com",
DEFAULT_API_EU_BASE_URI = "https://api-eu.vonage.com";

private final int timeoutMillis;
private final String apiBaseUri, restBaseUri, snsBaseUri, apiEuBaseUri;

private HttpConfig(Builder builder) {
if ((timeoutMillis = builder.timeoutMillis) < 10) {
throw new IllegalArgumentException("Timeout must be greater than 10ms.");
}
apiBaseUri = builder.apiBaseUri;
restBaseUri = builder.restBaseUri;
snsBaseUri = builder.snsBaseUri;
apiEuBaseUri = builder.apiEuBaseUri;
}

/**
* Gets the timeout setting for the underlying HTTP client configuration.
*
* @return The request timeout in milliseconds.
* @since 7.8.0
*/
public int getTimeoutMillis() {
return timeoutMillis;
}

public String getApiBaseUri() {
return apiBaseUri;
}
Expand Down Expand Up @@ -95,12 +109,31 @@ public static Builder builder() {
}

public static class Builder {
private int timeoutMillis = 60_000;
private String
apiBaseUri = DEFAULT_API_BASE_URI,
restBaseUri = DEFAULT_REST_BASE_URI,
snsBaseUri = DEFAULT_SNS_BASE_URI,
apiEuBaseUri = DEFAULT_API_EU_BASE_URI;

/**
* Sets the socket timeout for requests. By default, this is one minute (60000 ms).
* <br>
* Note that this timeout applies to both the connection and socket; therefore, it defines
* the maximum time for each stage of the request. For example, if set to 30 seconds, then
* establishing a connection may take 29 seconds and receiving a response may take 29 seconds
* without timing out (therefore a total of 58 seconds for the request).
*
* @param timeoutMillis The timeout in milliseconds.
*
* @return The Builder to keep building.
* @since 7.8.0
*/
public Builder timeoutMillis(int timeoutMillis) {
this.timeoutMillis = timeoutMillis;
return this;
}

/**
* @param apiBaseUri The base uri to use in place of {@link HttpConfig#DEFAULT_API_BASE_URI}
*
Expand Down Expand Up @@ -166,7 +199,6 @@ private String sanitizeUri(String uri) {
if (uri != null && uri.endsWith("/")) {
return uri.substring(0, uri.length() - 1);
}

return uri;
}
}
Expand Down
8 changes: 6 additions & 2 deletions src/main/java/com/vonage/client/HttpWrapper.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
*/
public class HttpWrapper {
private static final String CLIENT_NAME = "vonage-java-sdk";
private static final String CLIENT_VERSION = "7.7.0";
private static final String CLIENT_VERSION = "7.8.0";
private static final String JAVA_VERSION = System.getProperty("java.version");
private static final String USER_AGENT = String.format("%s/%s java/%s", CLIENT_NAME, CLIENT_VERSION, JAVA_VERSION);

Expand Down Expand Up @@ -93,7 +93,11 @@ protected HttpClient createHttpClient() {
// Need to work out a good value for the following:
// threadSafeClientConnManager.setValidateAfterInactivity();

RequestConfig requestConfig = RequestConfig.custom().build();
RequestConfig requestConfig = RequestConfig.custom()
.setConnectTimeout(httpConfig.getTimeoutMillis())
.setConnectionRequestTimeout(httpConfig.getTimeoutMillis())
.setSocketTimeout(httpConfig.getTimeoutMillis())
.build();

return HttpClientBuilder.create()
.setConnectionManager(connectionManager)
Expand Down
15 changes: 10 additions & 5 deletions src/main/java/com/vonage/client/VonageClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,11 @@ HttpWrapper getHttpWrapper() {
return httpWrapper;
}

/**
* Entry point for constructing an instance of this class.
*
* @return A new Builder with default initial configuration.
*/
public static Builder builder() {
return new Builder();
}
Expand All @@ -218,15 +223,12 @@ public static class Builder {
private AuthCollection authCollection;
private HttpConfig httpConfig = HttpConfig.defaultConfig();
private HttpClient httpClient;
private String applicationId;
private String apiKey;
private String apiSecret;
private String signatureSecret;
private String applicationId, apiKey, apiSecret, signatureSecret;
private byte[] privateKeyContents;
private HashUtil.HashType hashType = HashUtil.HashType.MD5;

/**
* @param httpConfig Configuration options for the {@link HttpWrapper}
* @param httpConfig Configuration options for the {@link HttpWrapper}.
*
* @return This builder.
*/
Expand All @@ -239,7 +241,10 @@ public Builder httpConfig(HttpConfig httpConfig) {
* @param httpClient Custom implementation of {@link HttpClient}.
*
* @return This builder.
*
* @deprecated This method will be removed in the next major release.
*/
@Deprecated
public Builder httpClient(HttpClient httpClient) {
this.httpClient = httpClient;
return this;
Expand Down
Loading

0 comments on commit a6fb1a8

Please sign in to comment.