Open rocky05475 opened 7 years ago
This doesn't seem easy to implement on top of .NET APIs; we'd need to either use the TASKKILL windows utility or call into native APIs
@rocky05475 I looked into this a bit but I couldn't find a way to implement it that was not Windows or even Windows version-specific (some versions seem to have TSKILL instead of TASKILL).
With the new ProcessId property, it is relatively easy to do a kill tree operation on Windows using TASKILL (which can itself be fired off using a command).
Therefore, I'm going to close this for now. We can reconsider if there is more demand for this feature and/or we can figure out a robust way to do this that works everywhere.
Ran into this issue as well. Added an extension as a workaround and thought I would share in case it was useful for anyone else. Can only be used with .NET Core 3.0 which has a new overload for Kill() and should work cross platform. Unfortunately .net standard 2.0 and 2.1 do not yet support this api.
// DisposeOnExit(false) must be set to false
public static class CommandExtensions
{
public static async Task<Command> WaitAsync(this Command command, TimeSpan timeout, CancellationToken cancellationToken)
{
var cancelCompletionSource = new TaskCompletionSource<object>();
var delayTask = Task.Delay(timeout);
using (cancellationToken.Register(() => cancelCompletionSource.TrySetCanceled()))
{
await Task.WhenAny(command.Task, delayTask, cancelCompletionSource.Task);
if (delayTask.IsCompleted || cancelCompletionSource.Task.IsCanceled)
{
command.KillTree();
}
return command;
}
}
public static void KillTree(this Command command)
{
command.Process.Kill(true);
}
}
//usage: await cmd.WaitAsync(TimeSpan.FromSeconds(5), tokenSrc.Token);
@adamsd308 thanks this is very helpful. With this, I think we can add some APIs that are only on netcoreapp3.0+ to support this.
I think that the cleanest way to represent this in an actual library change would be a new command option:
options => options.OwnsEntireProcessTree(bool value = true)
When this option is set, the following behavioral changes will occur:
Kill
will call process.Kill(true)
options.Timeout(timeout)
will call process.Kill(true)
if the command times outoptions.CancellationToken(token)
will call process.Kill(true)
if the command gets canceledMy thinking is that either you'll be wanting to treat a command as owning its entire tree, or you won't. Either way, you'll want all the mechanisms for killing to be consistent. And, if you want to violate this you can always do so by accessing the underlying process directly through an extension like the one you wrote.
Does that seem reasonable?
KillTree() implementation for windows (for possible shimming):
KillTree() implementation for unix (for possible shimming):
@madelson adding the additional api for .netcore 3.0+ would be awesome.
This is a little bit hard to Implement but It's a killing feature.
For example: Command.Run("cmd", "/c robocopy..."); Command.KillTree(); // Kill both cmd.exe and robocopy.exe