diff --git a/.travis.yml b/.travis.yml index c5c1d1991..185d94257 100644 --- a/.travis.yml +++ b/.travis.yml @@ -36,3 +36,8 @@ after_success: # infrastructure. This should prevent the buffer overflow from # https://github.com/travis-ci/travis-ci/issues/5227 sudo: false + +# due to travis-ci changes in default build environment, +# this must be specify in order for oraclejdk8 to install +# https://blog.travis-ci.com/2019-04-15-xenial-default-build-environment +dist: trusty diff --git a/connectors/okhttp/src/main/java/org/openstack4j/connectors/okhttp/HttpCommand.java b/connectors/okhttp/src/main/java/org/openstack4j/connectors/okhttp/HttpCommand.java index 8bdbe2e5d..8b6e103a0 100644 --- a/connectors/okhttp/src/main/java/org/openstack4j/connectors/okhttp/HttpCommand.java +++ b/connectors/okhttp/src/main/java/org/openstack4j/connectors/okhttp/HttpCommand.java @@ -41,9 +41,10 @@ public final class HttpCommand { private static final Logger LOG = LoggerFactory.getLogger(HttpCommand.class); + private static OkHttpClient client; - private HttpRequest request; - private OkHttpClient client; + private final HttpRequest request; + private OkHttpClient reqClient; private Request.Builder clientReq; private int retries; @@ -63,7 +64,15 @@ public static HttpCommand create(HttpRequest request) { } private void initialize() { - OkHttpClient.Builder okHttpClientBuilder = new OkHttpClient.Builder(); + if (client == null) { + synchronized (HttpCommand.class) { + if (client == null) { + client = getClient(request.getConfig()); + } + } + } + + OkHttpClient.Builder okHttpClientBuilder = client.newBuilder(); Config config = request.getConfig(); if (config.getProxy() != null) { @@ -91,8 +100,8 @@ private void initialize() { if (HttpLoggingFilter.isLoggingEnabled()) { okHttpClientBuilder.addInterceptor(new LoggingInterceptor()); } - okHttpClientBuilder.connectionPool(getConnectionPool()); - client = okHttpClientBuilder.build(); + + reqClient = okHttpClientBuilder.build(); clientReq = new Request.Builder(); populateHeaders(request); populateQueryParams(request); @@ -101,7 +110,7 @@ private void initialize() { /** * Create ConnectionPool optimized for short lived client with little chance to reuse connections. */ - private ConnectionPool getConnectionPool() { + private static OkHttpClient getClient(Config config) { int maxIdleConnections = 0; // OkHttp creates "OkHttp ConnectionPool" thread per every ConnectionPool created to mange its connections. It // lives as long as the last connection made through it + its keep alive timeout. By default that it 5 min which @@ -109,7 +118,15 @@ private ConnectionPool getConnectionPool() { // at least). Setting strict keepAlive duration here so the connections and threads does not hang around longer // than necessary. int keepAliveDuration = 500; - return new ConnectionPool(maxIdleConnections, keepAliveDuration, TimeUnit.MILLISECONDS); + ConnectionPool cp = new ConnectionPool(maxIdleConnections, keepAliveDuration, TimeUnit.MILLISECONDS); + + // OkHttp performs best when you create a single `OkHttpClient` instance and reuse it for all of + // your HTTP calls. This is because each client holds its own connection pool and thread pools. + // Reusing connections and threads reduces latency and saves memory. Conversely, creating a client + // for each request wastes resources on idle pools. + OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder(); + clientBuilder.connectionPool(cp).build(); + return clientBuilder.build(); } /** @@ -138,7 +155,7 @@ else if(request.hasJson()) { body = RequestBody.create(null, Util.EMPTY_BYTE_ARRAY); } clientReq.method(request.getMethod().name(), body); - Call call = client.newCall(clientReq.build()); + Call call = reqClient.newCall(clientReq.build()); return call.execute(); } @@ -224,4 +241,4 @@ static class LoggingInterceptor implements Interceptor { return response; } } -} \ No newline at end of file +}