Skip to content

Commit ad43b97

Browse files
authored
Add process health-check for Azure so we can re-use named-pipes bound to existing healthy external processes (#5541)
1 parent 48fe24d commit ad43b97

File tree

3 files changed

+64
-3
lines changed

3 files changed

+64
-3
lines changed

communication/build.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ ext {
2626
minimumInstructionCoverage = 0.8
2727
excludedClassesCoverage = [
2828
'datadog.communication.ddagent.ExternalAgentLauncher',
29+
'datadog.communication.ddagent.ExternalAgentLauncher.NamedPipeHealthCheck',
2930
'datadog.communication.ddagent.SharedCommunicationObjects.FixedConfigUrlSupplier',
3031
'datadog.communication.ddagent.SharedCommunicationObjects.RetryConfigUrlSupplier',
3132
'datadog.communication.http.OkHttpUtils',

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

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

3+
import static datadog.trace.util.ProcessSupervisor.ALWAYS_READY;
4+
import static datadog.trace.util.ProcessSupervisor.Health.HEALTHY;
5+
import static datadog.trace.util.ProcessSupervisor.Health.NEVER_CHECKED;
6+
import static datadog.trace.util.ProcessSupervisor.Health.READY_TO_START;
7+
38
import datadog.trace.api.Config;
49
import datadog.trace.api.Platform;
510
import datadog.trace.util.ProcessSupervisor;
@@ -25,7 +30,9 @@ public ExternalAgentLauncher(Config config) {
2530
traceProcessBuilder.redirectError(DISCARD);
2631
traceProcessBuilder.command().addAll(config.getTraceAgentArgs());
2732

28-
traceProcessSupervisor = new ProcessSupervisor("datadog-trace-agent", traceProcessBuilder);
33+
traceProcessSupervisor =
34+
new ProcessSupervisor(
35+
"trace-agent", traceProcessBuilder, healthCheck(config.getAgentNamedPipe()));
2936
} else {
3037
log.warn("Trace agent path not set. Will not start trace agent process");
3138
}
@@ -36,7 +43,9 @@ public ExternalAgentLauncher(Config config) {
3643
dogStatsDProcessBuilder.redirectError(DISCARD);
3744
dogStatsDProcessBuilder.command().addAll(config.getDogStatsDArgs());
3845

39-
dogStatsDProcessSupervisor = new ProcessSupervisor("dogstatsd", dogStatsDProcessBuilder);
46+
dogStatsDProcessSupervisor =
47+
new ProcessSupervisor(
48+
"dogstatsd", dogStatsDProcessBuilder, healthCheck(config.getDogStatsDNamedPipe()));
4049
} else {
4150
log.warn("DogStatsD path not set. Will not start DogStatsD process");
4251
}
@@ -53,4 +62,53 @@ public void close() {
5362
dogStatsDProcessSupervisor.close();
5463
}
5564
}
65+
66+
private static ProcessSupervisor.HealthCheck healthCheck(String pipeName) {
67+
return null != pipeName && !pipeName.trim().isEmpty()
68+
? new NamedPipeHealthCheck(pipeName)
69+
: ALWAYS_READY;
70+
}
71+
72+
static final class NamedPipeHealthCheck implements ProcessSupervisor.HealthCheck {
73+
private static final String NAMED_PIPE_PREFIX = "\\\\.\\pipe\\";
74+
75+
private final File pipe;
76+
77+
NamedPipeHealthCheck(String pipeName) {
78+
if (pipeName.startsWith(NAMED_PIPE_PREFIX)) {
79+
this.pipe = new File(pipeName);
80+
} else {
81+
this.pipe = new File(NAMED_PIPE_PREFIX + pipeName);
82+
}
83+
}
84+
85+
@Override
86+
public ProcessSupervisor.Health run(ProcessSupervisor.Health previousHealth)
87+
throws InterruptedException {
88+
89+
// first-time round do a more detailed check for existing bound named-pipe
90+
if (previousHealth == NEVER_CHECKED) {
91+
92+
double delayMillis = 50;
93+
for (int retries = 0; retries < 7; retries++) {
94+
if (!pipe.exists()) {
95+
return READY_TO_START; // no longer bound, start our own external process
96+
}
97+
98+
// check at increasing intervals to make sure it's bound to a healthy process
99+
Thread.sleep((long) delayMillis);
100+
delayMillis = delayMillis * 1.75;
101+
}
102+
103+
return HEALTHY; // use existing external process
104+
}
105+
106+
// otherwise just check that the pipe is still bound
107+
if (pipe.exists()) {
108+
return HEALTHY; // keep using external process
109+
} else {
110+
return READY_TO_START; // start our own process
111+
}
112+
}
113+
}
56114
}

internal-api/src/main/java/datadog/trace/util/ProcessSupervisor.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ public interface HealthCheck {
2727
Health run(Health previousHealth) throws InterruptedException;
2828
}
2929

30+
public static final HealthCheck ALWAYS_READY = health -> READY_TO_START;
31+
3032
private static final Logger log = LoggerFactory.getLogger(ProcessSupervisor.class);
3133

3234
private static final long HEALTHY_DELAY_MILLIS = 10_000;
@@ -50,7 +52,7 @@ public interface HealthCheck {
5052
* @param processBuilder Builder to create the process
5153
*/
5254
public ProcessSupervisor(String imageName, ProcessBuilder processBuilder) {
53-
this(imageName, processBuilder, health -> READY_TO_START);
55+
this(imageName, processBuilder, ALWAYS_READY);
5456
}
5557

5658
public ProcessSupervisor(

0 commit comments

Comments
 (0)