Skip to content

Commit

Permalink
Kill processes on process exit (#638)
Browse files Browse the repository at this point in the history
* Kill processes on exit
  • Loading branch information
colin-higgins authored Feb 12, 2020
1 parent cb80625 commit 8187def
Show file tree
Hide file tree
Showing 2 changed files with 101 additions and 31 deletions.
28 changes: 24 additions & 4 deletions src/Datadog.Trace/Tracer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public class Tracer : IDatadogTracer

static Tracer()
{
TracerSubProcessManager.StartStandaloneAgentProcessesWhenConfigured();
TracingProcessManager.StartProcesses();
// create the default global Tracer
Instance = new Tracer();
}
Expand Down Expand Up @@ -111,6 +111,7 @@ internal Tracer(TracerSettings settings, IAgentWriter agentWriter, ISampler samp

// Register callbacks to make sure we flush the traces before exiting
AppDomain.CurrentDomain.ProcessExit += CurrentDomain_ProcessExit;
AppDomain.CurrentDomain.DomainUnload += CurrentDomain_DomainUnload;
AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
Console.CancelKeyPress += Console_CancelKeyPress;

Expand Down Expand Up @@ -444,17 +445,36 @@ private void InitializeLibLogScopeEventSubscriber(IScopeManager scopeManager)

private void CurrentDomain_ProcessExit(object sender, EventArgs e)
{
_agentWriter.FlushAndCloseAsync().Wait();
RunShutdownTasks();
}

private void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
_agentWriter.FlushAndCloseAsync().Wait();
RunShutdownTasks();
}

private void Console_CancelKeyPress(object sender, ConsoleCancelEventArgs e)
{
_agentWriter.FlushAndCloseAsync().Wait();
RunShutdownTasks();
}

private void CurrentDomain_DomainUnload(object sender, EventArgs e)
{
RunShutdownTasks();
}

private void RunShutdownTasks()
{
try
{
_agentWriter.FlushAndCloseAsync().Wait();
}
catch (Exception ex)
{
DatadogLogging.RegisterStartupLog(log => log.Error(ex, "Error flushing traces on shutdown."));
}

TracingProcessManager.StopProcesses();
}

private void HeartbeatCallback(object state)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Threading;
Expand All @@ -8,42 +9,72 @@

namespace Datadog.Trace
{
internal class TracerSubProcessManager
internal class TracingProcessManager
{
private static Task _traceAgentMonitor;
private static Task _dogStatsDMonitor;
private static readonly List<ProcessMetadata> Processes = new List<ProcessMetadata>()
{
new ProcessMetadata()
{
Name = "datadog-trace-agent",
ProcessPathKey = ConfigurationKeys.TraceAgentPath,
ProcessArgumentsKey = ConfigurationKeys.TraceAgentArgs,
},
new ProcessMetadata()
{
Name = "dogstatsd",
ProcessPathKey = ConfigurationKeys.DogStatsDPath,
ProcessArgumentsKey = ConfigurationKeys.DogStatsDArgs,
}
};

public static void StartStandaloneAgentProcessesWhenConfigured()
public static void StopProcesses()
{
try
foreach (var subProcessMetadata in Processes)
{
var traceAgentPath = Environment.GetEnvironmentVariable(ConfigurationKeys.TraceAgentPath);
SafelyKillProcess(subProcessMetadata);
}
}

if (!string.IsNullOrWhiteSpace(traceAgentPath))
{
var traceProcessArgs = Environment.GetEnvironmentVariable(ConfigurationKeys.TraceAgentArgs);
_traceAgentMonitor = StartProcessWithKeepAlive(traceAgentPath, traceProcessArgs);
}
else
public static void StartProcesses()
{
try
{
foreach (var subProcessMetadata in Processes)
{
DatadogLogging.RegisterStartupLog(log => log.Debug("There is no path configured for {0}.", ConfigurationKeys.TraceAgentPath));
}

var dogStatsDPath = Environment.GetEnvironmentVariable(ConfigurationKeys.DogStatsDPath);
var processPath = Environment.GetEnvironmentVariable(subProcessMetadata.ProcessPathKey);

if (!string.IsNullOrWhiteSpace(dogStatsDPath))
{
var dogStatsDArgs = Environment.GetEnvironmentVariable(ConfigurationKeys.DogStatsDArgs);
_dogStatsDMonitor = StartProcessWithKeepAlive(dogStatsDPath, dogStatsDArgs);
if (!string.IsNullOrWhiteSpace(processPath))
{
var processArgs = Environment.GetEnvironmentVariable(subProcessMetadata.ProcessArgumentsKey);
subProcessMetadata.KeepAliveTask =
StartProcessWithKeepAlive(processPath, processArgs, subProcessMetadata);
}
else
{
DatadogLogging.RegisterStartupLog(log => log.Debug("There is no path configured for {0}.", subProcessMetadata.Name));
}
}
else
}
catch (Exception ex)
{
DatadogLogging.RegisterStartupLog(log => log.Error(ex, "Error when attempting to start standalone agent processes."));
}
}

private static void SafelyKillProcess(ProcessMetadata metadata)
{
try
{
if (metadata.Process != null && !metadata.Process.HasExited)
{
DatadogLogging.RegisterStartupLog(log => log.Debug("There is no path configured for {0}.", ConfigurationKeys.DogStatsDPath));
metadata.Process.Kill();
}

metadata.KeepAliveTask?.Dispose();
}
catch (Exception ex)
{
DatadogLogging.RegisterStartupLog(log => log.Error(ex, "Error when attempting to start standalone agent processes."));
DatadogLogging.RegisterStartupLog(log => log.Error(ex, "Failed to verify halt of the {0} process.", metadata.Name));
}
}

Expand All @@ -66,7 +97,7 @@ private static bool ProgramIsRunning(string fullPath)
return false;
}

private static Task StartProcessWithKeepAlive(string path, string args)
private static Task StartProcessWithKeepAlive(string path, string args, ProcessMetadata metadata)
{
DatadogLogging.RegisterStartupLog(log => log.Debug("Starting keep alive for {0}.", path));

Expand All @@ -82,6 +113,12 @@ private static Task StartProcessWithKeepAlive(string path, string args)
{
try
{
if (metadata.Process != null && metadata.Process.HasExited == false)
{
DatadogLogging.RegisterStartupLog(log => log.Debug("We already have an active reference to {0}.", path));
continue;
}
if (ProgramIsRunning(path))
{
DatadogLogging.RegisterStartupLog(log => log.Debug("{0} is already running.", path));
Expand All @@ -97,11 +134,11 @@ private static Task StartProcessWithKeepAlive(string path, string args)
DatadogLogging.RegisterStartupLog(log => log.Debug("Starting {0}.", path));
var process = Process.Start(startInfo);
metadata.Process = Process.Start(startInfo);
Thread.Sleep(150);
Thread.Sleep(200);
if (process == null || process.HasExited)
if (metadata.Process == null || metadata.Process.HasExited)
{
DatadogLogging.RegisterStartupLog(log => log.Error("{0} has failed to start.", path));
sequentialFailures++;
Expand Down Expand Up @@ -136,5 +173,18 @@ private static Task StartProcessWithKeepAlive(string path, string args)
}
});
}

private class ProcessMetadata
{
public string Name { get; set; }

public Process Process { get; set; }

public Task KeepAliveTask { get; set; }

public string ProcessPathKey { get; set; }

public string ProcessArgumentsKey { get; set; }
}
}
}

0 comments on commit 8187def

Please sign in to comment.