mirror of https://github.com/dapr/java-sdk.git
Fix high mem usage due to many OkHttpClient instances. (#373)
This commit is contained in:
parent
604eff8cd4
commit
eb7763f126
|
@ -9,6 +9,7 @@ import io.dapr.config.Properties;
|
||||||
import okhttp3.OkHttpClient;
|
import okhttp3.OkHttpClient;
|
||||||
|
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A builder for the DaprHttp.
|
* A builder for the DaprHttp.
|
||||||
|
@ -16,21 +17,30 @@ import java.time.Duration;
|
||||||
public class DaprHttpBuilder {
|
public class DaprHttpBuilder {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Read timeout for http calls.
|
* Singleton OkHttpClient.
|
||||||
*/
|
*/
|
||||||
private static final Duration DEFAULT_READ_TIMEOUT = Duration.ofSeconds(60);
|
private static final AtomicReference<OkHttpClient> OK_HTTP_CLIENT = new AtomicReference<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Static lock object.
|
||||||
|
*/
|
||||||
|
private static final Object LOCK = new Object();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Read timeout used to build object.
|
* Read timeout used to build object.
|
||||||
*/
|
*/
|
||||||
private Duration readTimeout = DEFAULT_READ_TIMEOUT;
|
private Duration readTimeout = Duration.ofSeconds(Properties.HTTP_CLIENT_READTIMEOUTSECONDS.get());
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the read timeout duration for the instance to be built.
|
* Sets the read timeout duration for the instance to be built.
|
||||||
*
|
*
|
||||||
|
* <p>Instead, set environment variable "DAPR_HTTP_CLIENT_READTIMEOUTSECONDS",
|
||||||
|
* or system property "dapr.http.client.readtimeoutseconds".
|
||||||
|
*
|
||||||
* @param duration Read timeout duration.
|
* @param duration Read timeout duration.
|
||||||
* @return Same builder instance.
|
* @return Same builder instance.
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public DaprHttpBuilder withReadTimeout(Duration duration) {
|
public DaprHttpBuilder withReadTimeout(Duration duration) {
|
||||||
this.readTimeout = duration;
|
this.readTimeout = duration;
|
||||||
return this;
|
return this;
|
||||||
|
@ -52,9 +62,17 @@ public class DaprHttpBuilder {
|
||||||
* @return Instance of {@link DaprHttp}
|
* @return Instance of {@link DaprHttp}
|
||||||
*/
|
*/
|
||||||
private DaprHttp buildDaprHttp() {
|
private DaprHttp buildDaprHttp() {
|
||||||
|
if (OK_HTTP_CLIENT.get() == null) {
|
||||||
|
synchronized (LOCK) {
|
||||||
|
if (OK_HTTP_CLIENT.get() == null) {
|
||||||
OkHttpClient.Builder builder = new OkHttpClient.Builder();
|
OkHttpClient.Builder builder = new OkHttpClient.Builder();
|
||||||
builder.readTimeout(this.readTimeout);
|
builder.readTimeout(this.readTimeout);
|
||||||
OkHttpClient okHttpClient = builder.build();
|
OkHttpClient okHttpClient = builder.build();
|
||||||
return new DaprHttp(Properties.SIDECAR_IP.get(), Properties.HTTP_PORT.get(), okHttpClient);
|
OK_HTTP_CLIENT.set(okHttpClient);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new DaprHttp(Properties.SIDECAR_IP.get(), Properties.HTTP_PORT.get(), OK_HTTP_CLIENT.get());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,6 +38,11 @@ public class Properties {
|
||||||
*/
|
*/
|
||||||
private static final Charset DEFAULT_STRING_CHARSET = StandardCharsets.UTF_8;
|
private static final Charset DEFAULT_STRING_CHARSET = StandardCharsets.UTF_8;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dapr's default timeout in seconds for HTTP client reads.
|
||||||
|
*/
|
||||||
|
private static final Integer DEFAULT_HTTP_CLIENT_READTIMEOUTSECONDS = 60;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* IP for Dapr's sidecar.
|
* IP for Dapr's sidecar.
|
||||||
*/
|
*/
|
||||||
|
@ -86,4 +91,12 @@ public class Properties {
|
||||||
"DAPR_STRING_CHARSET",
|
"DAPR_STRING_CHARSET",
|
||||||
DEFAULT_STRING_CHARSET,
|
DEFAULT_STRING_CHARSET,
|
||||||
(s) -> Charset.forName(s));
|
(s) -> Charset.forName(s));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dapr's timeout in seconds for HTTP client reads.
|
||||||
|
*/
|
||||||
|
public static final Property<Integer> HTTP_CLIENT_READTIMEOUTSECONDS = new IntegerProperty(
|
||||||
|
"dapr.http.client.readtimeoutseconds",
|
||||||
|
"DAPR_HTTP_CLIENT_READTIMEOUTSECONDS",
|
||||||
|
DEFAULT_HTTP_CLIENT_READTIMEOUTSECONDS);
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,37 +9,26 @@ import okhttp3.OkHttpClient;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.time.Duration;
|
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
|
||||||
import static org.junit.Assert.assertNotNull;
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
import static org.junit.Assert.assertSame;
|
||||||
|
|
||||||
public class DaprHttpBuilderTest {
|
public class DaprHttpBuilderTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void withReadTimeout() throws Exception {
|
public void singletonOkHttpClient() throws Exception {
|
||||||
DaprHttpBuilder daprHttpBuilder = new DaprHttpBuilder();
|
DaprHttp daprHttp = new DaprHttpBuilder().build();
|
||||||
Duration duration = Duration.ofSeconds(999);
|
DaprHttp anotherDaprHttp = new DaprHttpBuilder().build();
|
||||||
daprHttpBuilder.build();
|
|
||||||
DaprHttpBuilder dapr = daprHttpBuilder.withReadTimeout(duration);
|
|
||||||
assertNotNull(dapr);
|
|
||||||
|
|
||||||
DaprHttp daprHttp = daprHttpBuilder.build();
|
assertSame(getOkHttpClient(daprHttp), getOkHttpClient(anotherDaprHttp));
|
||||||
assertOKHttpPropertyValue(daprHttp, "readTimeoutMillis", (int)duration.toMillis());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final void assertOKHttpPropertyValue(DaprHttp daprHttp, String propertyName, Object expectedValue) throws Exception {
|
private static OkHttpClient getOkHttpClient(DaprHttp daprHttp) throws Exception {
|
||||||
// First, get okHttpClient.
|
|
||||||
Field httpClientField = DaprHttp.class.getDeclaredField("httpClient");
|
Field httpClientField = DaprHttp.class.getDeclaredField("httpClient");
|
||||||
httpClientField.setAccessible(true);
|
httpClientField.setAccessible(true);
|
||||||
OkHttpClient okHttpClient = (OkHttpClient) httpClientField.get(daprHttp);
|
OkHttpClient okHttpClient = (OkHttpClient) httpClientField.get(daprHttp);
|
||||||
assertNotNull(okHttpClient);
|
assertNotNull(okHttpClient);
|
||||||
|
return okHttpClient;
|
||||||
Field propertyField = OkHttpClient.class.getDeclaredField(propertyName);
|
|
||||||
propertyField.setAccessible(true);
|
|
||||||
Object value = propertyField.get(okHttpClient);
|
|
||||||
assertNotNull(value);
|
|
||||||
assertEquals(expectedValue, value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
Loading…
Reference in New Issue