Skip to content

Commit 8d5f5ac

Browse files
authored
Avoid performing blocking I/O operation on application thread (#8120)
* Avoid performing blocking I/O operation on application thread * Call checkDynamicConfig() at DSM start to load tracer config, then again at Inbox start to merge agent config * Make test more tolerant of parallel discover requests * Cleanup test side-effects
1 parent ab205f6 commit 8d5f5ac

File tree

4 files changed

+44
-24
lines changed

4 files changed

+44
-24
lines changed

communication/src/main/java/datadog/communication/ddagent/SharedCommunicationObjects.java

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package datadog.communication.ddagent;
22

33
import static datadog.communication.ddagent.TracerVersion.TRACER_VERSION;
4+
import static datadog.trace.util.AgentThreadFactory.AGENT_THREAD_GROUP;
45

56
import datadog.common.container.ContainerInfo;
67
import datadog.common.socket.SocketUtils;
@@ -9,6 +10,7 @@
910
import datadog.remoteconfig.ConfigurationPoller;
1011
import datadog.remoteconfig.DefaultConfigurationPoller;
1112
import datadog.trace.api.Config;
13+
import datadog.trace.util.AgentTaskScheduler;
1214
import java.util.concurrent.TimeUnit;
1315
import java.util.function.Supplier;
1416
import okhttp3.HttpUrl;
@@ -98,8 +100,11 @@ public DDAgentFeaturesDiscovery featuresDiscovery(Config config) {
98100
agentUrl,
99101
config.isTraceAgentV05Enabled(),
100102
config.isTracerMetricsEnabled());
101-
if (!"true".equalsIgnoreCase(System.getProperty("dd.test.no.early.discovery"))) {
102-
featuresDiscovery.discover();
103+
if (AGENT_THREAD_GROUP.equals(Thread.currentThread().getThreadGroup())) {
104+
featuresDiscovery.discover(); // safe to run on same thread
105+
} else {
106+
// avoid performing blocking I/O operation on application thread
107+
AgentTaskScheduler.INSTANCE.execute(featuresDiscovery::discover);
103108
}
104109
}
105110
return featuresDiscovery;

dd-java-agent/agent-debugger/src/test/java/com/datadog/debugger/agent/DebuggerAgentTest.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -122,11 +122,11 @@ public void runEnabledWithDatadogAgent() throws InterruptedException, IOExceptio
122122
ConfigurationPoller configurationPoller =
123123
(ConfigurationPoller) sharedCommunicationObjects.configurationPoller(Config.get());
124124
configurationPoller.start();
125-
RecordedRequest request = datadogAgentServer.takeRequest(5, TimeUnit.SECONDS);
126-
assertNotNull(request);
127-
assertEquals("/info", request.getPath());
128-
request = datadogAgentServer.takeRequest(5, TimeUnit.SECONDS);
129-
assertNotNull(request);
125+
RecordedRequest request;
126+
do {
127+
request = datadogAgentServer.takeRequest(5, TimeUnit.SECONDS);
128+
assertNotNull(request);
129+
} while ("/info".equals(request.getPath()));
130130
assertEquals("/v0.7/config", request.getPath());
131131
DebuggerAgent.stop();
132132
datadogAgentServer.shutdown();

dd-trace-core/src/main/java/datadog/trace/core/datastreams/DefaultDataStreamsMonitoring.java

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -136,21 +136,7 @@ public DefaultDataStreamsMonitoring(
136136

137137
@Override
138138
public void start() {
139-
if (features.getDataStreamsEndpoint() == null) {
140-
features.discoverIfOutdated();
141-
}
142-
143-
agentSupportsDataStreams = features.supportsDataStreams();
144139
checkDynamicConfig();
145-
146-
if (!configSupportsDataStreams) {
147-
log.debug("Data streams is disabled");
148-
} else if (!agentSupportsDataStreams) {
149-
log.debug("Data streams is disabled or not supported by agent");
150-
}
151-
152-
nextFeatureCheck = timeSource.getCurrentTimeNanos() + FEATURE_CHECK_INTERVAL_NANOS;
153-
154140
cancellation =
155141
AgentTaskScheduler.INSTANCE.scheduleAtFixedRate(
156142
new ReportTask(), this, bucketDurationNanos, bucketDurationNanos, TimeUnit.NANOSECONDS);
@@ -341,6 +327,22 @@ private StatsBucket getStatsBucket(final long timestamp, final String serviceNam
341327

342328
@Override
343329
public void run() {
330+
331+
if (features.getDataStreamsEndpoint() == null) {
332+
features.discoverIfOutdated();
333+
}
334+
335+
agentSupportsDataStreams = features.supportsDataStreams();
336+
checkDynamicConfig();
337+
338+
if (!configSupportsDataStreams) {
339+
log.debug("Data streams is disabled");
340+
} else if (!agentSupportsDataStreams) {
341+
log.debug("Data streams is disabled or not supported by agent");
342+
}
343+
344+
nextFeatureCheck = timeSource.getCurrentTimeNanos() + FEATURE_CHECK_INTERVAL_NANOS;
345+
344346
Thread currentThread = Thread.currentThread();
345347
while (!currentThread.isInterrupted()) {
346348
try {

dd-trace-core/src/test/groovy/datadog/trace/core/propagation/XRayHttpInjectorTest.groovy

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import datadog.trace.api.DDTraceId
66
import datadog.trace.api.DynamicConfig
77
import datadog.trace.api.time.TimeSource
88
import datadog.trace.bootstrap.instrumentation.api.AgentTracer.NoopPathwayContext
9+
import datadog.trace.core.datastreams.DataStreamsMonitoring
910

1011
import static datadog.trace.api.sampling.PrioritySampling.*
1112
import static datadog.trace.api.sampling.SamplingMechanism.*
@@ -25,7 +26,11 @@ class XRayHttpInjectorTest extends DDCoreSpecification {
2526
setup:
2627
def writer = new ListWriter()
2728
def timeSource = Mock(TimeSource)
28-
def tracer = tracerBuilder().writer(writer).timeSource(timeSource).build()
29+
def tracer = tracerBuilder()
30+
.dataStreamsMonitoring(Mock(DataStreamsMonitoring))
31+
.writer(writer)
32+
.timeSource(timeSource)
33+
.build()
2934
final DDSpanContext mockedContext =
3035
new DDSpanContext(
3136
DDTraceId.from("$traceId"),
@@ -76,7 +81,11 @@ class XRayHttpInjectorTest extends DDCoreSpecification {
7681
setup:
7782
def writer = new ListWriter()
7883
def timeSource = Mock(TimeSource)
79-
def tracer = tracerBuilder().writer(writer).timeSource(timeSource).build()
84+
def tracer = tracerBuilder()
85+
.dataStreamsMonitoring(Mock(DataStreamsMonitoring))
86+
.writer(writer)
87+
.timeSource(timeSource)
88+
.build()
8089
def headers = [
8190
'X-Amzn-Trace-Id' : "Root=1-00000000-00000000${traceId.padLeft(16, '0')};Parent=${spanId.padLeft(16, '0')}"
8291
]
@@ -136,7 +145,11 @@ class XRayHttpInjectorTest extends DDCoreSpecification {
136145
setup:
137146
def writer = new ListWriter()
138147
def timeSource = Mock(TimeSource)
139-
def tracer = tracerBuilder().writer(writer).timeSource(timeSource).build()
148+
def tracer = tracerBuilder()
149+
.dataStreamsMonitoring(Mock(DataStreamsMonitoring))
150+
.writer(writer)
151+
.timeSource(timeSource)
152+
.build()
140153
final DDSpanContext mockedContext =
141154
new DDSpanContext(
142155
DDTraceId.from("1"),

0 commit comments

Comments
 (0)