Skip to content

Commit 15aca0a

Browse files
adamsitnikKeboo
andauthored
Moving CancelOnProcessTermination out of middleware, better cancellation support (#2044)
* InvocationPipeline can be static * don't await a task-returning method when we can just return the task (less boilerplate and allocs) * don't register services when creating BindingContext in InvocationContext.BindingContext getter, as BindingContext ctor already does that * don't use BindingContext when there is no need to (it's expensive) * don't register CancellationToken inside ServiceProvider, pass the token in explicit way to Handler * move CancelOnProcessTermination out of middleware * RemoteExecutor does not support getting application arguments, Process.WaitForExitAsync is available only on .NET 7+ * extend Middleware with CancellationToken so it can be passed to Hosting Co-authored-by: Kevin B <[email protected]>
1 parent 76437b0 commit 15aca0a

File tree

44 files changed

+435
-660
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+435
-660
lines changed

samples/HostingPlayground/Program.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ namespace HostingPlayground
1212
{
1313
class Program
1414
{
15-
static async Task Main(string[] args) => await BuildCommandLine()
15+
static Task Main(string[] args) => BuildCommandLine()
1616
.UseHost(_ => Host.CreateDefaultBuilder(),
1717
host =>
1818
{

src/System.CommandLine.ApiCompatibility.Tests/ApiCompatibilityApprovalTests.System_CommandLine_Hosting_api_is_not_changed.approved.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ System.CommandLine.Hosting
1212
public static System.CommandLine.CommandLineBuilder UseHost(this System.CommandLine.CommandLineBuilder builder, System.Func<System.String[],Microsoft.Extensions.Hosting.IHostBuilder> hostBuilderFactory, System.Action<Microsoft.Extensions.Hosting.IHostBuilder> configureHost = null)
1313
public static Microsoft.Extensions.Hosting.IHostBuilder UseInvocationLifetime(this Microsoft.Extensions.Hosting.IHostBuilder host, System.CommandLine.Invocation.InvocationContext invocation, System.Action<InvocationLifetimeOptions> configureOptions = null)
1414
public class InvocationLifetime, Microsoft.Extensions.Hosting.IHostLifetime
15-
.ctor(Microsoft.Extensions.Options.IOptions<InvocationLifetimeOptions> options, Microsoft.Extensions.Hosting.IHostEnvironment environment, Microsoft.Extensions.Hosting.IHostApplicationLifetime applicationLifetime, System.CommandLine.Invocation.InvocationContext context = null, Microsoft.Extensions.Logging.ILoggerFactory loggerFactory = null)
15+
.ctor(Microsoft.Extensions.Options.IOptions<InvocationLifetimeOptions> options, Microsoft.Extensions.Hosting.IHostEnvironment environment, Microsoft.Extensions.Hosting.IHostApplicationLifetime applicationLifetime, Microsoft.Extensions.Logging.ILoggerFactory loggerFactory = null)
1616
public Microsoft.Extensions.Hosting.IHostApplicationLifetime ApplicationLifetime { get; }
1717
public Microsoft.Extensions.Hosting.IHostEnvironment Environment { get; }
1818
public InvocationLifetimeOptions Options { get; }

src/System.CommandLine.ApiCompatibility.Tests/ApiCompatibilityApprovalTests.System_CommandLine_NamingConventionBinder_api_is_not_changed.approved.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@
9999
public System.Void BindParameter(System.Reflection.ParameterInfo param, System.CommandLine.Argument argument)
100100
public System.Void BindParameter(System.Reflection.ParameterInfo param, System.CommandLine.Option option)
101101
public System.Int32 Invoke(System.CommandLine.Invocation.InvocationContext context)
102-
public System.Threading.Tasks.Task<System.Int32> InvokeAsync(System.CommandLine.Invocation.InvocationContext context)
102+
public System.Threading.Tasks.Task<System.Int32> InvokeAsync(System.CommandLine.Invocation.InvocationContext context, System.Threading.CancellationToken cancellationToken = null)
103103
public class ModelDescriptor
104104
public static ModelDescriptor FromType<T>()
105105
public static ModelDescriptor FromType(System.Type type)

src/System.CommandLine.ApiCompatibility.Tests/ApiCompatibilityApprovalTests.System_CommandLine_api_is_not_changed.approved.txt

Lines changed: 15 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -116,27 +116,27 @@ System.CommandLine
116116
public static class Handler
117117
public static System.Void SetHandler(this Command command, System.Action<System.CommandLine.Invocation.InvocationContext> handle)
118118
public static System.Void SetHandler(this Command command, System.Action handle)
119-
public static System.Void SetHandler(this Command command, System.Func<System.Threading.Tasks.Task> handle)
120-
public static System.Void SetHandler(this Command command, System.Func<System.CommandLine.Invocation.InvocationContext,System.Threading.Tasks.Task> handle)
119+
public static System.Void SetHandler(this Command command, System.Func<System.Threading.CancellationToken,System.Threading.Tasks.Task> handle)
120+
public static System.Void SetHandler(this Command command, System.Func<System.CommandLine.Invocation.InvocationContext,System.Threading.CancellationToken,System.Threading.Tasks.Task> handle)
121121
public static System.Void SetHandler<T>(this Command command, Action<T> handle, IValueDescriptor<T> symbol)
122-
public static System.Void SetHandler<T>(this Command command, Func<T,System.Threading.Tasks.Task> handle, IValueDescriptor<T> symbol)
122+
public static System.Void SetHandler<T>(this Command command, Func<T,System.Threading.CancellationToken,System.Threading.Tasks.Task> handle, IValueDescriptor<T> symbol)
123123
public static System.Void SetHandler<T1, T2>(this Command command, Action<T1,T2> handle, IValueDescriptor<T1> symbol1, IValueDescriptor<T2> symbol2)
124-
public static System.Void SetHandler<T1, T2>(this Command command, Func<T1,T2,System.Threading.Tasks.Task> handle, IValueDescriptor<T1> symbol1, IValueDescriptor<T2> symbol2)
124+
public static System.Void SetHandler<T1, T2>(this Command command, Func<T1,T2,System.Threading.CancellationToken,System.Threading.Tasks.Task> handle, IValueDescriptor<T1> symbol1, IValueDescriptor<T2> symbol2)
125125
public static System.Void SetHandler<T1, T2, T3>(this Command command, Action<T1,T2,T3> handle, IValueDescriptor<T1> symbol1, IValueDescriptor<T2> symbol2, IValueDescriptor<T3> symbol3)
126-
public static System.Void SetHandler<T1, T2, T3>(this Command command, Func<T1,T2,T3,System.Threading.Tasks.Task> handle, IValueDescriptor<T1> symbol1, IValueDescriptor<T2> symbol2, IValueDescriptor<T3> symbol3)
126+
public static System.Void SetHandler<T1, T2, T3>(this Command command, Func<T1,T2,T3,System.Threading.CancellationToken,System.Threading.Tasks.Task> handle, IValueDescriptor<T1> symbol1, IValueDescriptor<T2> symbol2, IValueDescriptor<T3> symbol3)
127127
public static System.Void SetHandler<T1, T2, T3, T4>(this Command command, Action<T1,T2,T3,T4> handle, IValueDescriptor<T1> symbol1, IValueDescriptor<T2> symbol2, IValueDescriptor<T3> symbol3, IValueDescriptor<T4> symbol4)
128-
public static System.Void SetHandler<T1, T2, T3, T4>(this Command command, Func<T1,T2,T3,T4,System.Threading.Tasks.Task> handle, IValueDescriptor<T1> symbol1, IValueDescriptor<T2> symbol2, IValueDescriptor<T3> symbol3, IValueDescriptor<T4> symbol4)
128+
public static System.Void SetHandler<T1, T2, T3, T4>(this Command command, Func<T1,T2,T3,T4,System.Threading.CancellationToken,System.Threading.Tasks.Task> handle, IValueDescriptor<T1> symbol1, IValueDescriptor<T2> symbol2, IValueDescriptor<T3> symbol3, IValueDescriptor<T4> symbol4)
129129
public static System.Void SetHandler<T1, T2, T3, T4, T5>(this Command command, Action<T1,T2,T3,T4,T5> handle, IValueDescriptor<T1> symbol1, IValueDescriptor<T2> symbol2, IValueDescriptor<T3> symbol3, IValueDescriptor<T4> symbol4, IValueDescriptor<T5> symbol5)
130-
public static System.Void SetHandler<T1, T2, T3, T4, T5>(this Command command, Func<T1,T2,T3,T4,T5,System.Threading.Tasks.Task> handle, IValueDescriptor<T1> symbol1, IValueDescriptor<T2> symbol2, IValueDescriptor<T3> symbol3, IValueDescriptor<T4> symbol4, IValueDescriptor<T5> symbol5)
130+
public static System.Void SetHandler<T1, T2, T3, T4, T5>(this Command command, Func<T1,T2,T3,T4,T5,System.Threading.CancellationToken,System.Threading.Tasks.Task> handle, IValueDescriptor<T1> symbol1, IValueDescriptor<T2> symbol2, IValueDescriptor<T3> symbol3, IValueDescriptor<T4> symbol4, IValueDescriptor<T5> symbol5)
131131
public static System.Void SetHandler<T1, T2, T3, T4, T5, T6>(this Command command, Action<T1,T2,T3,T4,T5,T6> handle, IValueDescriptor<T1> symbol1, IValueDescriptor<T2> symbol2, IValueDescriptor<T3> symbol3, IValueDescriptor<T4> symbol4, IValueDescriptor<T5> symbol5, IValueDescriptor<T6> symbol6)
132-
public static System.Void SetHandler<T1, T2, T3, T4, T5, T6>(this Command command, Func<T1,T2,T3,T4,T5,T6,System.Threading.Tasks.Task> handle, IValueDescriptor<T1> symbol1, IValueDescriptor<T2> symbol2, IValueDescriptor<T3> symbol3, IValueDescriptor<T4> symbol4, IValueDescriptor<T5> symbol5, IValueDescriptor<T6> symbol6)
132+
public static System.Void SetHandler<T1, T2, T3, T4, T5, T6>(this Command command, Func<T1,T2,T3,T4,T5,T6,System.Threading.CancellationToken,System.Threading.Tasks.Task> handle, IValueDescriptor<T1> symbol1, IValueDescriptor<T2> symbol2, IValueDescriptor<T3> symbol3, IValueDescriptor<T4> symbol4, IValueDescriptor<T5> symbol5, IValueDescriptor<T6> symbol6)
133133
public static System.Void SetHandler<T1, T2, T3, T4, T5, T6, T7>(this Command command, Action<T1,T2,T3,T4,T5,T6,T7> handle, IValueDescriptor<T1> symbol1, IValueDescriptor<T2> symbol2, IValueDescriptor<T3> symbol3, IValueDescriptor<T4> symbol4, IValueDescriptor<T5> symbol5, IValueDescriptor<T6> symbol6, IValueDescriptor<T7> symbol7)
134-
public static System.Void SetHandler<T1, T2, T3, T4, T5, T6, T7>(this Command command, Func<T1,T2,T3,T4,T5,T6,T7,System.Threading.Tasks.Task> handle, IValueDescriptor<T1> symbol1, IValueDescriptor<T2> symbol2, IValueDescriptor<T3> symbol3, IValueDescriptor<T4> symbol4, IValueDescriptor<T5> symbol5, IValueDescriptor<T6> symbol6, IValueDescriptor<T7> symbol7)
134+
public static System.Void SetHandler<T1, T2, T3, T4, T5, T6, T7>(this Command command, Func<T1,T2,T3,T4,T5,T6,T7,System.Threading.CancellationToken,System.Threading.Tasks.Task> handle, IValueDescriptor<T1> symbol1, IValueDescriptor<T2> symbol2, IValueDescriptor<T3> symbol3, IValueDescriptor<T4> symbol4, IValueDescriptor<T5> symbol5, IValueDescriptor<T6> symbol6, IValueDescriptor<T7> symbol7)
135135
public static System.Void SetHandler<T1, T2, T3, T4, T5, T6, T7, T8>(this Command command, Action<T1,T2,T3,T4,T5,T6,T7,T8> handle, IValueDescriptor<T1> symbol1, IValueDescriptor<T2> symbol2, IValueDescriptor<T3> symbol3, IValueDescriptor<T4> symbol4, IValueDescriptor<T5> symbol5, IValueDescriptor<T6> symbol6, IValueDescriptor<T7> symbol7, IValueDescriptor<T8> symbol8)
136-
public static System.Void SetHandler<T1, T2, T3, T4, T5, T6, T7, T8>(this Command command, Func<T1,T2,T3,T4,T5,T6,T7,T8,System.Threading.Tasks.Task> handle, IValueDescriptor<T1> symbol1, IValueDescriptor<T2> symbol2, IValueDescriptor<T3> symbol3, IValueDescriptor<T4> symbol4, IValueDescriptor<T5> symbol5, IValueDescriptor<T6> symbol6, IValueDescriptor<T7> symbol7, IValueDescriptor<T8> symbol8)
136+
public static System.Void SetHandler<T1, T2, T3, T4, T5, T6, T7, T8>(this Command command, Func<T1,T2,T3,T4,T5,T6,T7,T8,System.Threading.CancellationToken,System.Threading.Tasks.Task> handle, IValueDescriptor<T1> symbol1, IValueDescriptor<T2> symbol2, IValueDescriptor<T3> symbol3, IValueDescriptor<T4> symbol4, IValueDescriptor<T5> symbol5, IValueDescriptor<T6> symbol6, IValueDescriptor<T7> symbol7, IValueDescriptor<T8> symbol8)
137137
public interface ICommandHandler
138138
public System.Int32 Invoke(System.CommandLine.Invocation.InvocationContext context)
139-
public System.Threading.Tasks.Task<System.Int32> InvokeAsync(System.CommandLine.Invocation.InvocationContext context)
139+
public System.Threading.Tasks.Task<System.Int32> InvokeAsync(System.CommandLine.Invocation.InvocationContext context, System.Threading.CancellationToken cancellationToken = null)
140140
public interface IConsole : System.CommandLine.IO.IStandardError, System.CommandLine.IO.IStandardIn, System.CommandLine.IO.IStandardOut
141141
public abstract class IdentifierSymbol : Symbol
142142
public System.Collections.Generic.IReadOnlyCollection<System.String> Aliases { get; }
@@ -324,8 +324,8 @@ System.CommandLine.Help
324324
public System.Boolean Equals(TwoColumnHelpRow other)
325325
public System.Int32 GetHashCode()
326326
System.CommandLine.Invocation
327-
public class InvocationContext, System.IDisposable
328-
.ctor(System.CommandLine.ParseResult parseResult, System.CommandLine.IConsole console = null, System.Threading.CancellationToken cancellationToken = null)
327+
public class InvocationContext
328+
.ctor(System.CommandLine.ParseResult parseResult, System.CommandLine.IConsole console = null)
329329
public System.CommandLine.Binding.BindingContext BindingContext { get; }
330330
public System.CommandLine.IConsole Console { get; set; }
331331
public System.Int32 ExitCode { get; set; }
@@ -334,17 +334,15 @@ System.CommandLine.Invocation
334334
public System.CommandLine.LocalizationResources LocalizationResources { get; }
335335
public System.CommandLine.Parsing.Parser Parser { get; }
336336
public System.CommandLine.ParseResult ParseResult { get; set; }
337-
public System.Threading.CancellationToken GetCancellationToken()
338337
public System.Object GetValue(System.CommandLine.Option option)
339338
public T GetValue<T>(Option<T> option)
340339
public System.Object GetValue(System.CommandLine.Argument argument)
341340
public T GetValue<T>(Argument<T> argument)
342-
public System.Void LinkToken(System.Threading.CancellationToken token)
343341
public delegate InvocationMiddleware : System.MulticastDelegate, System.ICloneable, System.Runtime.Serialization.ISerializable
344342
.ctor(System.Object object, System.IntPtr method)
345-
public System.IAsyncResult BeginInvoke(InvocationContext context, System.Func<InvocationContext,System.Threading.Tasks.Task> next, System.AsyncCallback callback, System.Object object)
343+
public System.IAsyncResult BeginInvoke(InvocationContext context, System.Threading.CancellationToken cancellationToken, System.Func<InvocationContext,System.Threading.CancellationToken,System.Threading.Tasks.Task> next, System.AsyncCallback callback, System.Object object)
346344
public System.Threading.Tasks.Task EndInvoke(System.IAsyncResult result)
347-
public System.Threading.Tasks.Task Invoke(InvocationContext context, System.Func<InvocationContext,System.Threading.Tasks.Task> next)
345+
public System.Threading.Tasks.Task Invoke(InvocationContext context, System.Threading.CancellationToken cancellationToken, System.Func<InvocationContext,System.Threading.CancellationToken,System.Threading.Tasks.Task> next)
348346
public enum MiddlewareOrder : System.Enum, System.IComparable, System.IConvertible, System.IFormattable
349347
Default=0
350348
ErrorReporting=1000

src/System.CommandLine.Benchmarks/CommandLine/Perf_Parser_Directives_Suggest.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,8 @@ public void Setup()
4646
public string TestCmdArgs;
4747

4848
[Benchmark]
49-
public async Task InvokeSuggest()
50-
=> await _testParser.InvokeAsync(TestCmdArgs, _nullConsole);
49+
public Task InvokeSuggest()
50+
=> _testParser.InvokeAsync(TestCmdArgs, _nullConsole);
5151

5252
}
5353
}

src/System.CommandLine.Benchmarks/CommandLine/Perf_Parser_TypoCorrection.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ public IEnumerable<BdnParam<ParseResult>> GenerateTestParseResults()
5353

5454
[Benchmark]
5555
[ArgumentsSource(nameof(GenerateTestParseResults))]
56-
public async Task TypoCorrection(BdnParam<ParseResult> parseResult)
57-
=> await parseResult.Value.InvokeAsync(_nullConsole);
56+
public Task TypoCorrection(BdnParam<ParseResult> parseResult)
57+
=> parseResult.Value.InvokeAsync(_nullConsole);
5858
}
5959
}

src/System.CommandLine.Benchmarks/DragonFruit/Perf_CommandLine_EntryPoint.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -129,17 +129,17 @@ public void Setup()
129129
}
130130

131131
[Benchmark(Description = "ExecuteAssemblyAsync entry point search.")]
132-
public async Task SearchForStartingPointUsingReflection()
133-
=> await System.CommandLine.DragonFruit.CommandLine.ExecuteAssemblyAsync(
132+
public Task SearchForStartingPointUsingReflection()
133+
=> System.CommandLine.DragonFruit.CommandLine.ExecuteAssemblyAsync(
134134
_testAssembly,
135135
new string[] { },
136136
null,
137137
_testAssemblyXmlDocsFilePath,
138138
_nullConsole);
139139

140140
[Benchmark(Description = "ExecuteAssemblyAsync explicit entry point.")]
141-
public async Task SearchForStartingPointWhenGivenEntryPointClass()
142-
=> await System.CommandLine.DragonFruit.CommandLine.ExecuteAssemblyAsync(
141+
public Task SearchForStartingPointWhenGivenEntryPointClass()
142+
=> System.CommandLine.DragonFruit.CommandLine.ExecuteAssemblyAsync(
143143
_testAssembly,
144144
new string[] { },
145145
"PerfTestApp.Program",

src/System.CommandLine.Benchmarks/DragonFruit/Perf_CommandLine_Help.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,8 @@ public void Setup()
3939
}
4040

4141
[Benchmark(Description = "--help")]
42-
public async Task SearchForStartingPointWhenGivenEntryPointClass_Help()
43-
=> await System.CommandLine.DragonFruit.CommandLine.ExecuteAssemblyAsync(
42+
public Task SearchForStartingPointWhenGivenEntryPointClass_Help()
43+
=> System.CommandLine.DragonFruit.CommandLine.ExecuteAssemblyAsync(
4444
_testAssembly,
4545
new[] { "--help" },
4646
null,

src/System.CommandLine.DragonFruit/CommandLine.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ public static class CommandLine
2828
/// <param name="xmlDocsFilePath">Explicitly defined path to xml file containing XML Docs</param>
2929
/// <param name="console">Output console</param>
3030
/// <returns>The exit code.</returns>
31-
public static async Task<int> ExecuteAssemblyAsync(
31+
public static Task<int> ExecuteAssemblyAsync(
3232
Assembly entryAssembly,
3333
string[] args,
3434
string entryPointFullTypeName,
@@ -46,7 +46,7 @@ public static async Task<int> ExecuteAssemblyAsync(
4646
MethodInfo entryMethod = EntryPointDiscoverer.FindStaticEntryMethod(entryAssembly, entryPointFullTypeName);
4747

4848
//TODO The xml docs file name and location can be customized using <DocumentationFile> project property.
49-
return await InvokeMethodAsync(args, entryMethod, xmlDocsFilePath, null, console);
49+
return InvokeMethodAsync(args, entryMethod, xmlDocsFilePath, null, console);
5050
}
5151

5252
/// <summary>
@@ -79,7 +79,7 @@ public static int ExecuteAssembly(
7979
return InvokeMethod(args, entryMethod, xmlDocsFilePath, null, console);
8080
}
8181

82-
public static async Task<int> InvokeMethodAsync(
82+
public static Task<int> InvokeMethodAsync(
8383
string[] args,
8484
MethodInfo method,
8585
string xmlDocsFilePath = null,
@@ -88,7 +88,7 @@ public static async Task<int> InvokeMethodAsync(
8888
{
8989
Parser parser = BuildParser(method, xmlDocsFilePath, target);
9090

91-
return await parser.InvokeAsync(args, console);
91+
return parser.InvokeAsync(args, console);
9292
}
9393

9494
public static int InvokeMethod(

src/System.CommandLine.Generator/CommandHandlerSourceGenerator.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -115,10 +115,10 @@ private class GeneratedHandler_{handlerCount} : {ICommandHandlerType}
115115
}
116116

117117
builder.Append($@"
118-
public int Invoke(global::System.CommandLine.Invocation.InvocationContext context) => InvokeAsync(context).GetAwaiter().GetResult();");
118+
public int Invoke(global::System.CommandLine.Invocation.InvocationContext context) => InvokeAsync(context, global::System.Threading.CancellationToken.None).GetAwaiter().GetResult();");
119119

120120
builder.Append($@"
121-
public async global::System.Threading.Tasks.Task<int> InvokeAsync(global::System.CommandLine.Invocation.InvocationContext context)
121+
public async global::System.Threading.Tasks.Task<int> InvokeAsync(global::System.CommandLine.Invocation.InvocationContext context, global::System.Threading.CancellationToken cancellationToken)
122122
{{");
123123
builder.Append($@"
124124
{invocation.InvokeContents()}");

0 commit comments

Comments
 (0)