-
Notifications
You must be signed in to change notification settings - Fork 409
Description
OperationCanceledException Not Thrown without Config in Async Apps
This documentation (published 02 AUG 25) on Learn implies that System.CommandLine
will, without additional configuration, throw OperationCanceledException
when CTRL+C
is pressed allowing library consumers to gracefully handle any necessary cleanup or shutdown messaging.
Versions 2.0.0-beta5 and 2.0.0-beta6 both supported this behavior, but 2.0.0-beta7 and beyond break it.
Steps to reproduce
-
Clone and run https://github.com/mpatkisson/culbertson with .NET 9
> git clone https://github.com/mpatkisson/culbertson.git > cd culbertson > dotnet run --project ./src/Culbertson
-
Once the project is running, press
CTRL+C
.
Expected Behavior
This routine should be handled when CTRL+C
is pressed, thus printing these messages along with a slight delay for effect,
Termination requested. Cleaning up...
# 1 second delay
Cleanup complete. Exiting.
Actual Behavior
The program does exit when CTRL+C
is pressed, but OperationCanceledException
is never thrown, so cleanup messaging is not displayed.
Further Analysis
My guess is OperationCanceledException
should be thrown in Beta 7 as it is in Betas 5 and 6. If this was a design decision, then apologies (but the docs / code commentary are confusing if so).
7bb08a6
was the latest commit supporting the expected behavior. 7bb08a6
was followed by 3132acb | Separate parse from invocation configurations (#2606)
which had a lot of changes.
In the InvocationPipeline
, this switch case creates a ProcessTerminationHandler
only if InvocationConfiguration.ProcessTerminationTimeout
is non-null. Before Beta7 a default value of 2s was being set on CommandLineConfiguration.ProcessTerminationTimeout
like so
public TimeSpan? ProcessTerminationTimeout { get; set; } = TimeSpan.FromSeconds(2);
Commit 3132acb | Separate parse from invocation configurations (#2606)
renamed CommandLineConfiguration
to InvocationConfiguration
and dropped the default setting which now looks like this.
/// <summary>
/// Enables signaling and handling of process termination (Ctrl+C, SIGINT, SIGTERM) via a <see cref="CancellationToken"/>
/// that can be passed to a <see cref="CommandLineAction"/> during invocation.
/// If not provided, a default timeout of 2 seconds is enforced.
/// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/// </summary>
public TimeSpan? ProcessTerminationTimeout { get; set; }
Possible Fix
My sense is that the default value on InvocationConfiguration.ProcessTerminationTimeout
got lost in the mix of 3132acb and is still not fixed in the latest.
Re-adding the default brings behavior around CTRL+C
back in line with earlier versions and the Learn docs. I've tested this small change using this branch with success.