Skip to content

Repository files navigation

ChildProcessGuard

NuGetNuGet DownloadsBuild StatusLicense: MIT

A cross-platform .NET library that ensures child processes automatically terminate when the parent process exits unexpectedly.

Features

  • Cross-Platform Support: Works on Windows, Linux, and macOS
  • Automatic Cleanup: Child processes terminate when the parent exits
  • Windows Job Objects: Uses Job Objects for kernel-level process management on Windows
  • Process Tree Termination: Terminates all descendant processes via native APIs
  • Async/Await Support: Full asynchronous API with cancellation tokens
  • Process Monitoring: Real-time statistics and lifecycle events
  • Batch Processing: Start multiple processes with concurrency control
  • Thread-Safe: Supports concurrent operations
  • Graceful Shutdown: Configurable timeout and fallback mechanisms
  • Custom Logging: Pluggable log action delegate

Requirements

  • .NET Standard 2.0+ / .NET Framework 4.6.1+ / .NET Core 2.0+ / .NET 5+
  • .NET 10.0+

Supported Runtimes

Target FrameworkStatus
netstandard2.0Supported
netstandard2.1Supported
net10.0Supported

Installation

Package Manager

Install-Package ChildProcessGuard

.NET CLI

dotnet add package ChildProcessGuard

Quick Start

Basic Usage

usingChildProcessGuard;// Simple usage with automatic cleanupusingvarguardian=newProcessGuardian();varprocess=guardian.StartProcess("notepad.exe");Console.WriteLine($"Started process with PID: {process.Id}");// Process will be automatically terminated when guardian is disposed

Advanced Configuration

usingChildProcessGuard;// Configure with builder patternusingvarguardian=ProcessGuardianBuilder.Debug().WithKillTimeout(TimeSpan.FromSeconds(10)).WithMaxProcesses(50).WithDetailedLogging(true).WithAutoCleanup(true,TimeSpan.FromMinutes(1)).Build();// Set up event handlersguardian.ProcessError+=(sender,e)=>Console.WriteLine($"Error: {e.Operation} - {e.Exception.Message}");guardian.ProcessLifecycleEvent+=(sender,e)=>Console.WriteLine($"Event: {e.EventType} - {e.ProcessInfo}");varprocess=guardian.StartProcess("myapp.exe","--verbose");

Usage Examples

Environment Variables and Working Directory

usingvarguardian=newProcessGuardian();varenvVars=newDictionary<string,string>{{"DEBUG","true"},{"CONFIG_PATH","/etc/myapp/config.json"},{"LOG_LEVEL","verbose"}};varprocess=guardian.StartProcess("myapp.exe","--config config.json",workingDirectory:"/path/to/working/dir",environmentVariables:envVars);

Custom ProcessStartInfo

usingvarguardian=newProcessGuardian();varstartInfo=newProcessStartInfo{FileName="powershell.exe",Arguments="-NoProfile -Command \"Get-Process\"",UseShellExecute=false,RedirectStandardOutput=true,CreateNoWindow=true};varprocess=guardian.StartProcessWithStartInfo(startInfo);stringoutput=process.StandardOutput.ReadToEnd();

Batch Processing

usingvarguardian=ProcessGuardianBuilder.HighPerformance().Build();// Prepare multiple processesvarprocessInfos=Enumerable.Range(1,5).Select(i =>newProcessStartInfo("ping","127.0.0.1 -n 3")).ToList();// Start all processes concurrentlyvarprocesses=awaitguardian.StartProcessesBatchAsync(processInfos,maxConcurrency:3);// Wait for all to completeboolallCompleted=awaitguardian.WaitForAllProcessesAsync(TimeSpan.FromSeconds(30));Console.WriteLine($"All processes completed: {allCompleted}");

Process Monitoring

usingvarguardian=newProcessGuardian();// Start processesguardian.StartProcess("notepad.exe");guardian.StartProcess("calc.exe");// Get statisticsvarstats=guardian.GetStatistics();Console.WriteLine($"Total: {stats.TotalProcesses}, Running: {stats.RunningProcesses}");Console.WriteLine($"Memory Usage: {stats.TotalMemoryUsage/1024/1024:F1} MB");// Get detailed process informationvarrunningProcesses=guardian.GetProcessesByStatus(ProcessStatus.Running);foreach(varprocessInfoinrunningProcesses){Console.WriteLine($"Process: {processInfo}");Console.WriteLine($"Runtime: {processInfo.GetRuntime():hh\\:mm\\:ss}");}

Async Operations

usingvarguardian=newProcessGuardian();varcts=newCancellationTokenSource();// Start process asynchronouslyvarprocess=awaitguardian.StartProcessAsync("myapp.exe",cancellationToken:cts.Token);// Terminate all processesintterminated=awaitguardian.KillAllProcessesAsync(TimeSpan.FromSeconds(10));Console.WriteLine($"Terminated {terminated} processes");// Selective terminationintkilled=awaitguardian.TerminateProcessesWhere(
p =>p.GetRuntime()>TimeSpan.FromMinutes(5),TimeSpan.FromSeconds(5));

Custom Logging

// Route logs to your logging frameworkusingvarguardian=newProcessGuardianBuilder().WithDetailedLogging(true).WithLogAction(message =>logger.LogInformation(message)).Build();// Or use options directlyvaroptions=newProcessGuardianOptions{EnableDetailedLogging=true,LogAction= message =>Debug.WriteLine(message)};usingvarguardian=newProcessGuardian(options);

Cross-Platform Example

usingvarguardian=newProcessGuardian();stringexecutable,arguments;if(RuntimeInformation.IsOSPlatform(OSPlatform.Windows)){executable="cmd.exe";arguments="/c echo Hello from Windows";}else{executable="/bin/bash";arguments="-c 'echo Hello from Unix'";}varprocess=guardian.StartProcess(executable,arguments);awaitprocess.WaitForExitAsync();

Configuration Options

ProcessGuardianOptions

varoptions=newProcessGuardianOptions{ProcessKillTimeout=TimeSpan.FromSeconds(30),// Graceful termination timeoutEnableDetailedLogging=false,// Verbose loggingForceKillOnTimeout=true,// Force kill if timeout exceededMaxManagedProcesses=100,// Maximum concurrent processesAutoCleanupDisposedProcesses=true,// Auto cleanup exited processesCleanupInterval=TimeSpan.FromMinutes(5),// Cleanup check intervalThrowOnProcessOperationFailure=false,// Exception handling behaviorLogAction= msg =>Console.WriteLine(msg)// Custom log handler (optional)};usingvarguardian=newProcessGuardian(options);

Predefined Configurations

// High performance configurationusingvarhighPerf=ProcessGuardianBuilder.HighPerformance().Build();// Debug configuration with detailed loggingusingvardebug=ProcessGuardianBuilder.Debug().Build();// Custom configurationusingvarcustom=newProcessGuardianBuilder().WithKillTimeout(TimeSpan.FromSeconds(15)).WithMaxProcesses(200).WithDetailedLogging(true).WithLogAction(msg =>myLogger.Log(msg)).Build();

How It Works

Windows Implementation

  • Uses Windows Job Objects with JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE flag
  • Automatically terminates all child processes when the job handle is closed
  • Kernel-level guarantee for process cleanup
  • Per-process Job Object assignment tracking with graceful fallback

Unix Implementation (Linux/macOS)

  • Uses manual process tree tracking via /proc filesystem (Linux) and native APIs
  • Uses SIGTERM for graceful termination, SIGKILL for force termination
  • Enumerates and terminates descendant processes using process tree walking

Cross-Platform Failsafes

  • Hooks into AppDomain.ProcessExit and ConsoleCancelKeyPress events
  • Falls back to basic process termination if advanced features fail
  • Provides .NET 5+ features (e.g., WaitForExitAsync) for .NET Standard 2.0/2.1 compatibility

Best Practices

  1. Always use using statements or call Dispose() explicitly
  2. Configure appropriate timeouts based on process characteristics
  3. Handle events for production applications to track errors
  4. Use builder pattern for complex configurations
  5. Use LogAction to route logs to your logging framework instead of relying on Console.WriteLine
  6. Monitor statistics in long-running applications
  7. Test cross-platform behavior when targeting multiple operating systems

License

This project is licensed under the MIT License - see the LICENSE file for details.

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

Support

For issues, questions, or suggestions, please open an issue on GitHub.

About

Cross-platform .NET library that guarantees child process termination when the parent exits — Windows Job Objects, Linux /proc, macOS native APIs, full async support.

Topics

Resources

Security policy

Stars

7 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages