Skip to content

Moving CancelOnProcessTermination out of middleware, better cancellation support #2044

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 19 commits into from
Feb 18, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
8361a4a
add missing usings
adamsitnik Feb 6, 2023
02fb6a8
delay the allocation of linked list of CancellationTokenRegistrations
adamsitnik Feb 6, 2023
f4dd075
_source does not need to be volatile: it's initialized in ctor (alway…
adamsitnik Feb 6, 2023
2ae46df
InvocationPipeline can be static
adamsitnik Feb 6, 2023
e23d995
don't await a task-returning method when we can just return the task …
adamsitnik Feb 6, 2023
b25ebf7
don't register services when creating BindingContext in InvocationCon…
adamsitnik Feb 6, 2023
d3e6068
don't register CancellationToken twice in ServiceProvider
adamsitnik Feb 6, 2023
c24e3c5
don't use BindingContext when there is no need to (it's expensive)
adamsitnik Feb 6, 2023
91ac000
don't register CancellationToken inside ServiceProvider, pass the tok…
adamsitnik Feb 6, 2023
a5d21d0
move CancelOnProcessTermination out of middleware
adamsitnik Feb 6, 2023
cf466ca
fix EndToEndTestApp
adamsitnik Feb 6, 2023
0861eb9
SIGTERM fixes, test improvements
adamsitnik Feb 7, 2023
ef9c1a1
use the new PosixSignalRegistration type
adamsitnik Feb 7, 2023
d43d536
more improvements
adamsitnik Feb 13, 2023
158e469
fix compilation warnings
adamsitnik Feb 13, 2023
577765a
RemoteExecutor does not support getting application arguments, Proces…
adamsitnik Feb 13, 2023
6114d76
set CancellationToken cancellationToken to default by default (this i…
adamsitnik Feb 17, 2023
5905a9b
extend Middleware with CancellationToken so it can be passed to Hosting
adamsitnik Feb 17, 2023
510b4cd
Apply suggestions from code review
adamsitnik Feb 18, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion samples/HostingPlayground/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ namespace HostingPlayground
{
class Program
{
static async Task Main(string[] args) => await BuildCommandLine()
static Task Main(string[] args) => BuildCommandLine()
.UseHost(_ => Host.CreateDefaultBuilder(),
host =>
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ System.CommandLine.Hosting
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)
public static Microsoft.Extensions.Hosting.IHostBuilder UseInvocationLifetime(this Microsoft.Extensions.Hosting.IHostBuilder host, System.CommandLine.Invocation.InvocationContext invocation, System.Action<InvocationLifetimeOptions> configureOptions = null)
public class InvocationLifetime, Microsoft.Extensions.Hosting.IHostLifetime
.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)
.ctor(Microsoft.Extensions.Options.IOptions<InvocationLifetimeOptions> options, Microsoft.Extensions.Hosting.IHostEnvironment environment, Microsoft.Extensions.Hosting.IHostApplicationLifetime applicationLifetime, Microsoft.Extensions.Logging.ILoggerFactory loggerFactory = null)
public Microsoft.Extensions.Hosting.IHostApplicationLifetime ApplicationLifetime { get; }
public Microsoft.Extensions.Hosting.IHostEnvironment Environment { get; }
public InvocationLifetimeOptions Options { get; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@
public System.Void BindParameter(System.Reflection.ParameterInfo param, System.CommandLine.Argument argument)
public System.Void BindParameter(System.Reflection.ParameterInfo param, System.CommandLine.Option option)
public System.Int32 Invoke(System.CommandLine.Invocation.InvocationContext context)
public System.Threading.Tasks.Task<System.Int32> InvokeAsync(System.CommandLine.Invocation.InvocationContext context)
public System.Threading.Tasks.Task<System.Int32> InvokeAsync(System.CommandLine.Invocation.InvocationContext context, System.Threading.CancellationToken cancellationToken = null)
public class ModelDescriptor
public static ModelDescriptor FromType<T>()
public static ModelDescriptor FromType(System.Type type)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,27 +116,27 @@ System.CommandLine
public static class Handler
public static System.Void SetHandler(this Command command, System.Action<System.CommandLine.Invocation.InvocationContext> handle)
public static System.Void SetHandler(this Command command, System.Action handle)
public static System.Void SetHandler(this Command command, System.Func<System.Threading.Tasks.Task> handle)
public static System.Void SetHandler(this Command command, System.Func<System.CommandLine.Invocation.InvocationContext,System.Threading.Tasks.Task> handle)
public static System.Void SetHandler(this Command command, System.Func<System.Threading.CancellationToken,System.Threading.Tasks.Task> handle)
public static System.Void SetHandler(this Command command, System.Func<System.CommandLine.Invocation.InvocationContext,System.Threading.CancellationToken,System.Threading.Tasks.Task> handle)
public static System.Void SetHandler<T>(this Command command, Action<T> handle, IValueDescriptor<T> symbol)
public static System.Void SetHandler<T>(this Command command, Func<T,System.Threading.Tasks.Task> handle, IValueDescriptor<T> symbol)
public static System.Void SetHandler<T>(this Command command, Func<T,System.Threading.CancellationToken,System.Threading.Tasks.Task> handle, IValueDescriptor<T> symbol)
public static System.Void SetHandler<T1, T2>(this Command command, Action<T1,T2> handle, IValueDescriptor<T1> symbol1, IValueDescriptor<T2> symbol2)
public static System.Void SetHandler<T1, T2>(this Command command, Func<T1,T2,System.Threading.Tasks.Task> handle, IValueDescriptor<T1> symbol1, IValueDescriptor<T2> symbol2)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
public interface ICommandHandler
public System.Int32 Invoke(System.CommandLine.Invocation.InvocationContext context)
public System.Threading.Tasks.Task<System.Int32> InvokeAsync(System.CommandLine.Invocation.InvocationContext context)
public System.Threading.Tasks.Task<System.Int32> InvokeAsync(System.CommandLine.Invocation.InvocationContext context, System.Threading.CancellationToken cancellationToken = null)
public interface IConsole : System.CommandLine.IO.IStandardError, System.CommandLine.IO.IStandardIn, System.CommandLine.IO.IStandardOut
public abstract class IdentifierSymbol : Symbol
public System.Collections.Generic.IReadOnlyCollection<System.String> Aliases { get; }
Expand Down Expand Up @@ -324,8 +324,8 @@ System.CommandLine.Help
public System.Boolean Equals(TwoColumnHelpRow other)
public System.Int32 GetHashCode()
System.CommandLine.Invocation
public class InvocationContext, System.IDisposable
.ctor(System.CommandLine.ParseResult parseResult, System.CommandLine.IConsole console = null, System.Threading.CancellationToken cancellationToken = null)
public class InvocationContext
.ctor(System.CommandLine.ParseResult parseResult, System.CommandLine.IConsole console = null)
public System.CommandLine.Binding.BindingContext BindingContext { get; }
public System.CommandLine.IConsole Console { get; set; }
public System.Int32 ExitCode { get; set; }
Expand All @@ -334,17 +334,15 @@ System.CommandLine.Invocation
public System.CommandLine.LocalizationResources LocalizationResources { get; }
public System.CommandLine.Parsing.Parser Parser { get; }
public System.CommandLine.ParseResult ParseResult { get; set; }
public System.Threading.CancellationToken GetCancellationToken()
public System.Object GetValue(System.CommandLine.Option option)
public T GetValue<T>(Option<T> option)
public System.Object GetValue(System.CommandLine.Argument argument)
public T GetValue<T>(Argument<T> argument)
public System.Void LinkToken(System.Threading.CancellationToken token)
public delegate InvocationMiddleware : System.MulticastDelegate, System.ICloneable, System.Runtime.Serialization.ISerializable
.ctor(System.Object object, System.IntPtr method)
public System.IAsyncResult BeginInvoke(InvocationContext context, System.Func<InvocationContext,System.Threading.Tasks.Task> next, System.AsyncCallback callback, System.Object object)
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)
public System.Threading.Tasks.Task EndInvoke(System.IAsyncResult result)
public System.Threading.Tasks.Task Invoke(InvocationContext context, System.Func<InvocationContext,System.Threading.Tasks.Task> next)
public System.Threading.Tasks.Task Invoke(InvocationContext context, System.Threading.CancellationToken cancellationToken, System.Func<InvocationContext,System.Threading.CancellationToken,System.Threading.Tasks.Task> next)
public enum MiddlewareOrder : System.Enum, System.IComparable, System.IConvertible, System.IFormattable
Default=0
ErrorReporting=1000
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,8 @@ public void Setup()
public string TestCmdArgs;

[Benchmark]
public async Task InvokeSuggest()
=> await _testParser.InvokeAsync(TestCmdArgs, _nullConsole);
public Task InvokeSuggest()
=> _testParser.InvokeAsync(TestCmdArgs, _nullConsole);

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ public IEnumerable<BdnParam<ParseResult>> GenerateTestParseResults()

[Benchmark]
[ArgumentsSource(nameof(GenerateTestParseResults))]
public async Task TypoCorrection(BdnParam<ParseResult> parseResult)
=> await parseResult.Value.InvokeAsync(_nullConsole);
public Task TypoCorrection(BdnParam<ParseResult> parseResult)
=> parseResult.Value.InvokeAsync(_nullConsole);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -129,17 +129,17 @@ public void Setup()
}

[Benchmark(Description = "ExecuteAssemblyAsync entry point search.")]
public async Task SearchForStartingPointUsingReflection()
=> await System.CommandLine.DragonFruit.CommandLine.ExecuteAssemblyAsync(
public Task SearchForStartingPointUsingReflection()
=> System.CommandLine.DragonFruit.CommandLine.ExecuteAssemblyAsync(
_testAssembly,
new string[] { },
null,
_testAssemblyXmlDocsFilePath,
_nullConsole);

[Benchmark(Description = "ExecuteAssemblyAsync explicit entry point.")]
public async Task SearchForStartingPointWhenGivenEntryPointClass()
=> await System.CommandLine.DragonFruit.CommandLine.ExecuteAssemblyAsync(
public Task SearchForStartingPointWhenGivenEntryPointClass()
=> System.CommandLine.DragonFruit.CommandLine.ExecuteAssemblyAsync(
_testAssembly,
new string[] { },
"PerfTestApp.Program",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,8 @@ public void Setup()
}

[Benchmark(Description = "--help")]
public async Task SearchForStartingPointWhenGivenEntryPointClass_Help()
=> await System.CommandLine.DragonFruit.CommandLine.ExecuteAssemblyAsync(
public Task SearchForStartingPointWhenGivenEntryPointClass_Help()
=> System.CommandLine.DragonFruit.CommandLine.ExecuteAssemblyAsync(
_testAssembly,
new[] { "--help" },
null,
Expand Down
8 changes: 4 additions & 4 deletions src/System.CommandLine.DragonFruit/CommandLine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public static class CommandLine
/// <param name="xmlDocsFilePath">Explicitly defined path to xml file containing XML Docs</param>
/// <param name="console">Output console</param>
/// <returns>The exit code.</returns>
public static async Task<int> ExecuteAssemblyAsync(
public static Task<int> ExecuteAssemblyAsync(
Assembly entryAssembly,
string[] args,
string entryPointFullTypeName,
Expand All @@ -46,7 +46,7 @@ public static async Task<int> ExecuteAssemblyAsync(
MethodInfo entryMethod = EntryPointDiscoverer.FindStaticEntryMethod(entryAssembly, entryPointFullTypeName);

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

/// <summary>
Expand Down Expand Up @@ -79,7 +79,7 @@ public static int ExecuteAssembly(
return InvokeMethod(args, entryMethod, xmlDocsFilePath, null, console);
}

public static async Task<int> InvokeMethodAsync(
public static Task<int> InvokeMethodAsync(
string[] args,
MethodInfo method,
string xmlDocsFilePath = null,
Expand All @@ -88,7 +88,7 @@ public static async Task<int> InvokeMethodAsync(
{
Parser parser = BuildParser(method, xmlDocsFilePath, target);

return await parser.InvokeAsync(args, console);
return parser.InvokeAsync(args, console);
}

public static int InvokeMethod(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -115,10 +115,10 @@ private class GeneratedHandler_{handlerCount} : {ICommandHandlerType}
}

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

builder.Append($@"
public async global::System.Threading.Tasks.Task<int> InvokeAsync(global::System.CommandLine.Invocation.InvocationContext context)
public async global::System.Threading.Tasks.Task<int> InvokeAsync(global::System.CommandLine.Invocation.InvocationContext context, global::System.Threading.CancellationToken cancellationToken)
{{");
builder.Append($@"
{invocation.InvokeContents()}");
Expand Down
9 changes: 5 additions & 4 deletions src/System.CommandLine.Hosting.Tests/HostingHandlerTest.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System.CommandLine;
using System.CommandLine.Invocation;
using System.CommandLine.Parsing;
using System.Threading;
using System.Threading.Tasks;
using FluentAssertions;
using Microsoft.Extensions.DependencyInjection;
Expand Down Expand Up @@ -143,7 +144,7 @@ public int Invoke(InvocationContext context)
return Act();
}

public Task<int> InvokeAsync(InvocationContext context)
public Task<int> InvokeAsync(InvocationContext context, CancellationToken cancellationToken)
{
return Task.FromResult(Act());
}
Expand Down Expand Up @@ -176,7 +177,7 @@ public int Invoke(InvocationContext context)
return IntOption;
}

public Task<int> InvokeAsync(InvocationContext context)
public Task<int> InvokeAsync(InvocationContext context, CancellationToken cancellationToken)
{
service.Value = IntOption;
return Task.FromResult(IntOption);
Expand Down Expand Up @@ -222,9 +223,9 @@ public MyHandler(MyService service)

public string One { get; set; }

public int Invoke(InvocationContext context) => InvokeAsync(context).GetAwaiter().GetResult();
public int Invoke(InvocationContext context) => InvokeAsync(context, CancellationToken.None).GetAwaiter().GetResult();

public Task<int> InvokeAsync(InvocationContext context)
public Task<int> InvokeAsync(InvocationContext context, CancellationToken cancellationToken)
{
service.Value = IntOption;
service.StringValue = One;
Expand Down
Loading