11package 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+
38import datadog .trace .api .Config ;
49import datadog .trace .api .Platform ;
510import 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}
0 commit comments