Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
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
Prev Previous commit
support external cancellationToken
  • Loading branch information
neuecc committed Sep 7, 2025
commit d3d100e1bad25dd336a60ee760777045ddf6a8f2
29 changes: 21 additions & 8 deletions sandbox/GeneratorSandbox/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -47,19 +47,25 @@

var app = builder.ToConsoleAppBuilder();

var consoleAppLoger = ConsoleApp.ServiceProvider.GetRequiredService<ILogger<Program>>(); // already built service provider.
ConsoleApp.Log = msg => consoleAppLoger.LogDebug(msg);
ConsoleApp.LogError = msg => consoleAppLoger.LogError(msg);

app.UseFilter<CommandTracingFilter>();

app.Add("", async ([FromServices] ILogger<Program> logger) =>
app.Add("", async ([FromServices] ILogger<Program> logger/*, CancellationToken cancellationToken*/) =>
{
var cancellationToken = CancellationToken.None;

using var httpClient = new HttpClient();
var ms = await httpClient.GetStringAsync("https://www.microsoft.com");
var ms = await httpClient.GetStringAsync("https://www.microsoft.com", cancellationToken);
logger.LogInformation(ms);
var google = await httpClient.GetStringAsync("https://www.google.com");
var google = await httpClient.GetStringAsync("https://www.google.com", cancellationToken);
logger.LogInformation(google);

var ms2 = httpClient.GetStringAsync("https://www.microsoft.com");
var google2 = httpClient.GetStringAsync("https://www.google.com");
var apple2 = httpClient.GetStringAsync("https://www.apple.com");
var ms2 = httpClient.GetStringAsync("https://www.microsoft.com", cancellationToken);
var google2 = httpClient.GetStringAsync("https://www.google.com", cancellationToken);
var apple2 = httpClient.GetStringAsync("https://www.apple.com", cancellationToken);
await Task.WhenAll(ms2, google2, apple2);

logger.LogInformation(apple2.Result);
Expand Down Expand Up @@ -100,8 +106,15 @@ public override async Task InvokeAsync(ConsoleAppContext context, CancellationTo
{
if (activity != null)
{
activity.AddException(ex);
activity.SetStatus(ActivityStatusCode.Error);
if (ex is OperationCanceledException)
{
activity.SetStatus(ActivityStatusCode.Error, "Canceled");
}
else
{
activity.AddException(ex);
activity.SetStatus(ActivityStatusCode.Error);
}
}
throw;
}
Expand Down
41 changes: 23 additions & 18 deletions src/ConsoleAppFramework/ConsoleAppBaseCode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -371,9 +371,9 @@ static void ShowVersion()

static partial void ShowHelp(int helpId);

static async Task RunWithFilterAsync(string commandName, string[] args, int commandDepth, int escapeIndex, ConsoleAppFilter invoker)
static async Task RunWithFilterAsync(string commandName, string[] args, int commandDepth, int escapeIndex, ConsoleAppFilter invoker, CancellationToken cancellationToken)
{
using var posixSignalHandler = PosixSignalHandler.Register(Timeout);
using var posixSignalHandler = PosixSignalHandler.Register(Timeout, cancellationToken);
try
{
await Task.Run(() => invoker.InvokeAsync(new ConsoleAppContext(commandName, args, null, commandDepth, escapeIndex), posixSignalHandler.Token)).WaitAsync(posixSignalHandler.TimeoutToken);
Expand Down Expand Up @@ -411,16 +411,16 @@ sealed class PosixSignalHandler : IDisposable
PosixSignalRegistration? sigQuit;
PosixSignalRegistration? sigTerm;

PosixSignalHandler(TimeSpan timeout)
PosixSignalHandler(TimeSpan timeout, CancellationToken cancellationToken)
{
this.cancellationTokenSource = new CancellationTokenSource();
this.cancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
this.timeoutCancellationTokenSource = new CancellationTokenSource();
this.timeout = timeout;
}

public static PosixSignalHandler Register(TimeSpan timeout)
public static PosixSignalHandler Register(TimeSpan timeout, CancellationToken cancellationToken)
{
var handler = new PosixSignalHandler(timeout);
var handler = new PosixSignalHandler(timeout, cancellationToken);

Action<PosixSignalContext> handleSignal = handler.HandlePosixSignal;

Expand All @@ -443,6 +443,7 @@ public void Dispose()
sigInt?.Dispose();
sigQuit?.Dispose();
sigTerm?.Dispose();
cancellationTokenSource.Dispose();
timeoutCancellationTokenSource.Dispose();
}
}
Expand Down Expand Up @@ -482,10 +483,10 @@ public void UseFilter<T>() where T : ConsoleAppFilter { }
partial void AddCore(string commandName, Delegate command);

[MethodImpl(MethodImplOptions.AggressiveInlining)]
partial void RunCore(string[] args);
partial void RunCore(string[] args, CancellationToken cancellationToken);

[MethodImpl(MethodImplOptions.AggressiveInlining)]
partial void RunAsyncCore(string[] args, ref Task result);
partial void RunAsyncCore(string[] args, CancellationToken cancellationToken, ref Task result);

partial void BuildAndSetServiceProvider();

Expand Down Expand Up @@ -546,15 +547,14 @@ internal static partial class ConsoleApp
internal partial class ConsoleAppBuilder
{
public void Run(string[] args) => Run(args, true);
public void Run(string[] args, CancellationToken cancellationToken) => Run(args, true, cancellationToken);

public Task RunAsync(string[] args) => RunAsync(args, true);

public void Run(string[] args, bool disposeService)
public void Run(string[] args, bool disposeService, CancellationToken cancellationToken = default)
{
BuildAndSetServiceProvider();
try
{
RunCore(args);
RunCore(args, cancellationToken);
}
finally
{
Expand All @@ -568,13 +568,16 @@ public void Run(string[] args, bool disposeService)
}
}

public async Task RunAsync(string[] args, bool disposeService)
public Task RunAsync(string[] args) => RunAsync(args, true);
public Task RunAsync(string[] args, CancellationToken cancellationToken) => RunAsync(args, true, cancellationToken);

public async Task RunAsync(string[] args, bool disposeService, CancellationToken cancellationToken = default)
{
BuildAndSetServiceProvider();
try
{
Task? task = null;
RunAsyncCore(args, ref task!);
RunAsyncCore(args, cancellationToken, ref task!);
if (task != null)
{
await task;
Expand Down Expand Up @@ -621,8 +624,9 @@ internal static partial class ConsoleApp
internal partial class ConsoleAppBuilder
{
public void Run(string[] args) => Run(args, true, true, true);
public void Run(string[] args, CancellationToken cancellationToken) => Run(args, true, true, true, cancellationToken);

public void Run(string[] args, bool startHost, bool stopHost, bool disposeService)
public void Run(string[] args, bool startHost, bool stopHost, bool disposeService, CancellationToken cancellationToken = default)
{
BuildAndSetServiceProvider();
Microsoft.Extensions.Hosting.IHost? host = ConsoleApp.ServiceProvider?.GetService(typeof(Microsoft.Extensions.Hosting.IHost)) as Microsoft.Extensions.Hosting.IHost;
Expand All @@ -632,7 +636,7 @@ public void Run(string[] args, bool startHost, bool stopHost, bool disposeServic
{
host?.StartAsync().GetAwaiter().GetResult();
}
RunCore(args);
RunCore(args, cancellationToken);
}
finally
{
Expand All @@ -651,8 +655,9 @@ public void Run(string[] args, bool startHost, bool stopHost, bool disposeServic
}

public Task RunAsync(string[] args) => RunAsync(args, true, true, true);
public Task RunAsync(string[] args, CancellationToken cancellationToken) => RunAsync(args, true, true, true, cancellationToken);

public async Task RunAsync(string[] args, bool startHost, bool stopHost, bool disposeService)
public async Task RunAsync(string[] args, bool startHost, bool stopHost, bool disposeService, CancellationToken cancellationToken = default)
{
BuildAndSetServiceProvider();
Microsoft.Extensions.Hosting.IHost? host = ConsoleApp.ServiceProvider?.GetService(typeof(Microsoft.Extensions.Hosting.IHost)) as Microsoft.Extensions.Hosting.IHost;
Expand All @@ -663,7 +668,7 @@ public async Task RunAsync(string[] args, bool startHost, bool stopHost, bool di
await host?.StartAsync();
}
Task? task = null;
RunAsyncCore(args, ref task!);
RunAsyncCore(args, cancellationToken, ref task!);
if (task != null)
{
await task;
Expand Down
16 changes: 9 additions & 7 deletions src/ConsoleAppFramework/Emitter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,9 @@ public void EmitRun(SourceBuilder sb, CommandWithId commandWithId, bool isRunAsy
}

var commandDepthEscapeIndex = emitForBuilder ? ", int commandDepth, int escapeIndex" : "";
var filterCancellationToken = command.HasFilter ? ", ConsoleAppContext context, CancellationToken cancellationToken" : "";
var filterCancellationToken = command.HasFilter ? ", ConsoleAppContext context, CancellationToken cancellationToken"
: emitForBuilder ? ", CancellationToken __ExternalCancellationToken__"
: "";

if (!emitForBuilder)
{
Expand Down Expand Up @@ -83,7 +85,7 @@ public void EmitRun(SourceBuilder sb, CommandWithId commandWithId, bool isRunAsy
// prepare argument variables
if (hasCancellationToken)
{
sb.AppendLine("using var posixSignalHandler = PosixSignalHandler.Register(Timeout);");
sb.AppendLine("using var posixSignalHandler = PosixSignalHandler.Register(Timeout, __ExternalCancellationToken__);");
}
if (hasConsoleAppContext)
{
Expand Down Expand Up @@ -412,7 +414,7 @@ public void EmitBuilder(SourceBuilder sb, CommandWithId[] commandIds, bool emitS
if (emitSync)
{
sb.AppendLine();
using (sb.BeginBlock("partial void RunCore(string[] args)"))
using (sb.BeginBlock("partial void RunCore(string[] args, CancellationToken cancellationToken)"))
{
if (hasRootCommand)
{
Expand All @@ -431,7 +433,7 @@ public void EmitBuilder(SourceBuilder sb, CommandWithId[] commandIds, bool emitS
if (emitAsync)
{
sb.AppendLine();
using (sb.BeginBlock("partial void RunAsyncCore(string[] args, ref Task result)"))
using (sb.BeginBlock("partial void RunAsyncCore(string[] args, CancellationToken cancellationToken, ref Task result)"))
{
if (hasRootCommand)
{
Expand Down Expand Up @@ -559,16 +561,16 @@ void EmitLeafCommand(CommandWithId? command)
{
if (!isRunAsync)
{
sb.AppendLine($"RunCommand{command.Id}(args, {depth}, args.AsSpan().IndexOf(\"--\"){commandArgs});");
sb.AppendLine($"RunCommand{command.Id}(args, {depth}, args.AsSpan().IndexOf(\"--\"){commandArgs}, cancellationToken);");
}
else
{
sb.AppendLine($"result = RunCommand{command.Id}Async(args, {depth}, args.AsSpan().IndexOf(\"--\"){commandArgs});");
sb.AppendLine($"result = RunCommand{command.Id}Async(args, {depth}, args.AsSpan().IndexOf(\"--\"){commandArgs}, cancellationToken);");
}
}
else
{
var invokeCode = $"RunWithFilterAsync(\"{command.Command.Name}\", args, {depth}, args.AsSpan().IndexOf(\"--\"), new Command{command.Id}Invoker({commandArgs.TrimStart(',', ' ')}).BuildFilter())";
var invokeCode = $"RunWithFilterAsync(\"{command.Command.Name}\", args, {depth}, args.AsSpan().IndexOf(\"--\"), new Command{command.Id}Invoker({commandArgs.TrimStart(',', ' ')}).BuildFilter(), cancellationToken)";
if (!isRunAsync)
{
sb.AppendLine($"{invokeCode}.GetAwaiter().GetResult();");
Expand Down