Run JDK HTTP sender on non-daemon threads. (#7322)

Co-authored-by: Jack Berg <jberg@newrelic.com>
This commit is contained in:
Alex Brown 2025-05-15 22:12:25 +01:00 committed by GitHub
parent 6bd13ffcbc
commit deeceebe8d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
1 changed files with 22 additions and 6 deletions

View File

@ -13,6 +13,7 @@ import io.opentelemetry.exporter.internal.marshal.Marshaler;
import io.opentelemetry.sdk.common.CompletableResultCode; import io.opentelemetry.sdk.common.CompletableResultCode;
import io.opentelemetry.sdk.common.export.ProxyOptions; import io.opentelemetry.sdk.common.export.ProxyOptions;
import io.opentelemetry.sdk.common.export.RetryPolicy; import io.opentelemetry.sdk.common.export.RetryPolicy;
import io.opentelemetry.sdk.internal.DaemonThreadFactory;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.OutputStream; import java.io.OutputStream;
@ -32,8 +33,9 @@ import java.util.StringJoiner;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.function.Predicate; import java.util.function.Predicate;
@ -101,7 +103,7 @@ public final class JdkHttpSender implements HttpSender {
.map(RetryPolicy::getRetryExceptionPredicate) .map(RetryPolicy::getRetryExceptionPredicate)
.orElse(JdkHttpSender::isRetryableException); .orElse(JdkHttpSender::isRetryableException);
if (executorService == null) { if (executorService == null) {
this.executorService = Executors.newFixedThreadPool(5); this.executorService = newExecutor();
this.managedExecutor = true; this.managedExecutor = true;
} else { } else {
this.executorService = executorService; this.executorService = executorService;
@ -133,6 +135,16 @@ public final class JdkHttpSender implements HttpSender {
executorService); executorService);
} }
private static ExecutorService newExecutor() {
return new ThreadPoolExecutor(
0,
Integer.MAX_VALUE,
60,
TimeUnit.SECONDS,
new SynchronousQueue<>(),
new DaemonThreadFactory("jdkhttp-executor"));
}
private static HttpClient configureClient( private static HttpClient configureClient(
@Nullable SSLContext sslContext, @Nullable SSLContext sslContext,
long connectionTimeoutNanos, long connectionTimeoutNanos,
@ -224,7 +236,8 @@ public final class JdkHttpSender implements HttpSender {
Thread.currentThread().interrupt(); Thread.currentThread().interrupt();
break; // Break out and return response or throw break; // Break out and return response or throw
} }
// If after sleeping we've exceeded timeoutNanos, break out and return response or throw // If after sleeping we've exceeded timeoutNanos, break out and return
// response or throw
if ((System.nanoTime() - startTimeNanos) >= timeoutNanos) { if ((System.nanoTime() - startTimeNanos) >= timeoutNanos) {
break; break;
} }
@ -305,12 +318,15 @@ public final class JdkHttpSender implements HttpSender {
} }
private static boolean isRetryableException(IOException throwable) { private static boolean isRetryableException(IOException throwable) {
// Almost all IOExceptions we've encountered are transient retryable, so we opt out of specific // Almost all IOExceptions we've encountered are transient retryable, so we
// opt out of specific
// IOExceptions that are unlikely to resolve rather than opting in. // IOExceptions that are unlikely to resolve rather than opting in.
// Known retryable IOException messages: "Connection reset", "/{remote ip}:{remote port} GOAWAY // Known retryable IOException messages: "Connection reset", "/{remote
// ip}:{remote port} GOAWAY
// received" // received"
// Known retryable HttpTimeoutException messages: "request timed out" // Known retryable HttpTimeoutException messages: "request timed out"
// Known retryable HttpConnectTimeoutException messages: "HTTP connect timed out" // Known retryable HttpConnectTimeoutException messages: "HTTP connect timed
// out"
return !(throwable instanceof SSLException); return !(throwable instanceof SSLException);
} }