Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,20 @@ SeatsioClient client = new SeatsioClient(Region.EU, <WORKSPACE SECRET KEY>).maxR

Passing in 0 disables exponential backoff completely. In that case, the client will never retry a failed request.

## Timeouts

By default, the client waits up to 10 seconds to establish a connection, and up to 30 seconds for the server to respond.

To change these timeouts, create the `SeatsioClient` as follows:

```java
SeatsioClient client = new SeatsioClient(Region.EU, <WORKSPACE SECRET KEY>)
.connectTimeout(Duration.ofSeconds(5))
.socketTimeout(Duration.ofSeconds(60));
```

The timeouts apply per `SeatsioClient` instance. A request that times out is not retried: a `SeatsioException` is thrown.

## Multi-threading

It's perfectly fine to re-use an instance of `SeatsioClient` in different threads. All methods are thread-safe.
Expand Down
12 changes: 12 additions & 0 deletions src/main/java/seatsio/SeatsioClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
import seatsio.util.UnirestWrapper;
import seatsio.workspaces.Workspaces;

import java.time.Duration;

public class SeatsioClient {

private final String baseUrl;
Expand Down Expand Up @@ -56,6 +58,16 @@ public SeatsioClient maxRetries(int maxRetries) {
return this;
}

public SeatsioClient connectTimeout(Duration connectTimeout) {
unirest.connectTimeout(connectTimeout);
return this;
}

public SeatsioClient socketTimeout(Duration socketTimeout) {
unirest.socketTimeout(socketTimeout);
return this;
}

public String getBaseUrl() {
return baseUrl;
}
Expand Down
18 changes: 17 additions & 1 deletion src/main/java/seatsio/util/UnirestWrapper.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,21 @@
import kong.unirest.*;
import seatsio.SeatsioException;

import java.time.Duration;
import java.util.concurrent.atomic.AtomicReference;

import static java.nio.charset.StandardCharsets.UTF_8;

public class UnirestWrapper {

private static UnirestInstance unirest = new UnirestInstance(new Config()
.socketTimeout(10000)
.connectTimeout(10000)
.socketTimeout(30000)
.concurrency(200, 200));

private int maxRetries = 5;
private int connectTimeoutMillis = 10000;
private int socketTimeoutMillis = 30000;
private final String secretKey;
private final String workspaceKey;

Expand All @@ -36,6 +40,8 @@ private byte[] execute(HttpRequest request, int retryCount) {
AtomicReference<RawResponse> response = new AtomicReference<>();
AtomicReference<byte[]> responseBody = new AtomicReference<>();
request.header("X-Client-Lib", "Java");
request.connectTimeout(connectTimeoutMillis);
request.socketTimeout(socketTimeoutMillis);
authenticate(request, secretKey, workspaceKey).thenConsume(r -> {
response.set((RawResponse) r);
responseBody.set(response.get().getContentAsBytes());
Expand Down Expand Up @@ -93,6 +99,16 @@ public UnirestWrapper maxRetries(int maxRetries) {
return this;
}

public UnirestWrapper connectTimeout(Duration connectTimeout) {
this.connectTimeoutMillis = Math.toIntExact(connectTimeout.toMillis());
return this;
}

public UnirestWrapper socketTimeout(Duration socketTimeout) {
this.socketTimeoutMillis = Math.toIntExact(socketTimeout.toMillis());
return this;
}

public static void reinitializeHttpConnectionPool() {
unirest.shutDown(false);
}
Expand Down
52 changes: 52 additions & 0 deletions src/test/java/seatsio/TimeoutTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package seatsio;

import com.sun.net.httpserver.HttpServer;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import java.net.InetSocketAddress;
import java.time.Duration;
import java.time.Instant;
import java.util.concurrent.atomic.AtomicInteger;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;

public class TimeoutTest {

private HttpServer server;
private final AtomicInteger requestCount = new AtomicInteger();

@BeforeEach
public void startSlowServer() throws Exception {
server = HttpServer.create(new InetSocketAddress("localhost", 0), 0);
server.createContext("/", exchange -> {
requestCount.incrementAndGet();
try {
Thread.sleep(3000);
} catch (InterruptedException ignored) {
}
exchange.sendResponseHeaders(200, -1);
exchange.close();
});
server.start();
}

@AfterEach
public void stopServer() {
server.stop(0);
}

@Test
public void socketTimeoutIsConfigurableAndTimedOutRequestsAreNotRetried() {
SeatsioClient client = new SeatsioClient("secretKey", null, "http://localhost:" + server.getAddress().getPort())
.socketTimeout(Duration.ofMillis(300));

Instant start = Instant.now();
assertThatThrownBy(() -> client.charts.retrieve("someChart")).isInstanceOf(SeatsioException.class);

assertThat(Duration.between(start, Instant.now())).isLessThan(Duration.ofSeconds(2));
assertThat(requestCount.get()).isEqualTo(1);
}
}
Loading