Cancellation
Read this page before putting a timeout on a process run: RunAsync accepts a CancellationToken, but it cancels
the wait for the process to exit, not the process itself.
For example, to stop waiting after five minutes:
using var cts = new CancellationTokenSource(TimeSpan.FromMinutes(5));
try
{
var result = await processRunner.RunAsync(
new ProcessRunOptions("dotnet", "test"),
cts.Token);
}
catch (OperationCanceledException)
{
// The wait was abandoned after 5 minutes.
}
What cancellation does — and doesn't — do
Important
Cancelling the token aborts the wait, not the process. The underlying OS process keeps
running after OperationCanceledException is thrown.
When the token fires:
- The returned task faults with
OperationCanceledException(aTaskCanceledException). - Output captured up to that point is discarded — you do not receive a partial
ProcessRunResult. - The child process continues running to completion (or until it is killed externally).
This design keeps the runner predictable: it never kills processes it didn't decide to start killing, which matters for tools that hold locks or write files non-atomically.
Killing the process yourself
If you need hard timeout semantics — "stop waiting and terminate the tool" — run the process through a wrapper that owns process-tree termination, or kill by name/ID after cancellation:
try
{
await processRunner.RunAsync(options, cts.Token);
}
catch (OperationCanceledException)
{
foreach (var p in System.Diagnostics.Process.GetProcessesByName("stuck-tool"))
p.Kill(entireProcessTree: true);
throw;
}
Synchronous Run
The synchronous Run method has no cancellation support — it blocks until the process exits.
Prefer RunAsync whenever a timeout or cooperative cancellation may be needed.
See also
- Running Processes: sync versus async execution.
- Handling Failures: the other ways a run can end without a result.
- IProcessRunner