Skip to content

Commit b277764

Browse files
authored
Merge pull request #193 from Cysharp/external_cancel
Support external CancellationToken
2 parents f04825a + d3d100e commit b277764

File tree

5 files changed

+140
-96
lines changed

5 files changed

+140
-96
lines changed

sandbox/GeneratorSandbox/GeneratorSandbox.csproj

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,11 @@
1717
</PropertyGroup>
1818

1919
<ItemGroup>
20-
<!--<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="9.0.0" />
21-
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="9.0.0" />-->
22-
<!--<PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.6" />-->
23-
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.4.0" />
24-
<!--<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="9.0.0" />-->
25-
<!--<PackageReference Include="ZLogger" Version="2.5.9" />-->
20+
<PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.6" />
21+
<PackageReference Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.9.0" />
22+
<PackageReference Include="OpenTelemetry.Extensions.Hosting" Version="1.9.0" />
23+
<PackageReference Include="OpenTelemetry.Instrumentation.Runtime" Version="1.9.0" />
24+
<PackageReference Include="OpenTelemetry.Instrumentation.Http" Version="1.9.0" />
2625
</ItemGroup>
2726

2827
<ItemGroup>
Lines changed: 102 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -1,84 +1,122 @@
11
using ConsoleAppFramework;
2+
using Microsoft.Extensions.DependencyInjection;
3+
using Microsoft.Extensions.Hosting;
4+
using Microsoft.Extensions.Logging;
5+
using OpenTelemetry.Logs;
6+
using OpenTelemetry.Metrics;
7+
using OpenTelemetry.Resources;
8+
using OpenTelemetry.Trace;
9+
using System.Diagnostics;
210

3-
args = ["hello"];
11+
// Use SigNoz profiling: (view: http://localhost:8080/ )
12+
// git clone https://github.com/SigNoz/signoz.git
13+
// cd signoz/deploy/docker
14+
// docker compose up
15+
Environment.SetEnvironmentVariable("OTEL_EXPORTER_OTLP_ENDPOINT", "http://localhost:4317"); // 4317 or 4318
416

5-
var builder = ConsoleApp.Create();
17+
var builder = Host.CreateApplicationBuilder(args);
618

7-
builder.UseFilter<NopFilter1>();
8-
builder.UseFilter<NopFilter2>();
19+
builder.Logging.AddOpenTelemetry(logging =>
20+
{
21+
logging.IncludeFormattedMessage = true;
22+
logging.IncludeScopes = true;
23+
});
924

10-
builder.Add<MyClass>();
25+
builder.Services.AddOpenTelemetry()
26+
.ConfigureResource(resource =>
27+
{
28+
resource.AddService("ConsoleAppFramework Telemetry Sample");
29+
})
30+
.WithMetrics(metrics =>
31+
{
32+
metrics.AddRuntimeInstrumentation()
33+
.AddHttpClientInstrumentation()
34+
.AddOtlpExporter();
35+
})
36+
.WithTracing(tracing =>
37+
{
38+
tracing.SetSampler(new AlwaysOnSampler())
39+
.AddHttpClientInstrumentation()
40+
.AddSource(ConsoleAppFrameworkSampleActivitySource.Name)
41+
.AddOtlpExporter();
42+
})
43+
.WithLogging(logging =>
44+
{
45+
logging.AddOtlpExporter();
46+
});
1147

12-
await builder.RunAsync(args);
48+
var app = builder.ToConsoleAppBuilder();
1349

14-
[ConsoleAppFilter<NopFilter3>]
15-
[ConsoleAppFilter<NopFilter4>]
16-
public class MyClass
17-
{
18-
[ConsoleAppFilter<NopFilter5>]
19-
[ConsoleAppFilter<NopFilter6>]
20-
public void Hello()
21-
{
22-
Console.Write("abcde");
23-
}
24-
}
50+
var consoleAppLoger = ConsoleApp.ServiceProvider.GetRequiredService<ILogger<Program>>(); // already built service provider.
51+
ConsoleApp.Log = msg => consoleAppLoger.LogDebug(msg);
52+
ConsoleApp.LogError = msg => consoleAppLoger.LogError(msg);
2553

26-
internal class NopFilter1(ConsoleAppFilter next)
27-
: ConsoleAppFilter(next)
28-
{
29-
public override Task InvokeAsync(ConsoleAppContext context, CancellationToken cancellationToken)
30-
{
31-
Console.Write(1);
32-
return Next.InvokeAsync(context, cancellationToken);
33-
}
34-
}
54+
app.UseFilter<CommandTracingFilter>();
3555

36-
internal class NopFilter2(ConsoleAppFilter next)
37-
: ConsoleAppFilter(next)
56+
app.Add("", async ([FromServices] ILogger<Program> logger/*, CancellationToken cancellationToken*/) =>
3857
{
39-
public override Task InvokeAsync(ConsoleAppContext context, CancellationToken cancellationToken)
40-
{
41-
Console.Write(2);
42-
return Next.InvokeAsync(context, cancellationToken);
43-
}
44-
}
58+
var cancellationToken = CancellationToken.None;
4559

46-
internal class NopFilter3(ConsoleAppFilter next)
47-
: ConsoleAppFilter(next)
48-
{
49-
public override Task InvokeAsync(ConsoleAppContext context, CancellationToken cancellationToken)
50-
{
51-
Console.Write(3);
52-
return Next.InvokeAsync(context, cancellationToken);
53-
}
54-
}
60+
using var httpClient = new HttpClient();
61+
var ms = await httpClient.GetStringAsync("https://www.microsoft.com", cancellationToken);
62+
logger.LogInformation(ms);
63+
var google = await httpClient.GetStringAsync("https://www.google.com", cancellationToken);
64+
logger.LogInformation(google);
5565

56-
internal class NopFilter4(ConsoleAppFilter next)
57-
: ConsoleAppFilter(next)
58-
{
59-
public override Task InvokeAsync(ConsoleAppContext context, CancellationToken cancellationToken)
60-
{
61-
Console.Write(4);
62-
return Next.InvokeAsync(context, cancellationToken);
63-
}
64-
}
66+
var ms2 = httpClient.GetStringAsync("https://www.microsoft.com", cancellationToken);
67+
var google2 = httpClient.GetStringAsync("https://www.google.com", cancellationToken);
68+
var apple2 = httpClient.GetStringAsync("https://www.apple.com", cancellationToken);
69+
await Task.WhenAll(ms2, google2, apple2);
6570

66-
internal class NopFilter5(ConsoleAppFilter next)
67-
: ConsoleAppFilter(next)
71+
logger.LogInformation(apple2.Result);
72+
73+
logger.LogInformation("OK");
74+
});
75+
76+
await app.RunAsync(args);
77+
78+
public static class ConsoleAppFrameworkSampleActivitySource
6879
{
69-
public override Task InvokeAsync(ConsoleAppContext context, CancellationToken cancellationToken)
70-
{
71-
Console.Write(5);
72-
return Next.InvokeAsync(context, cancellationToken);
73-
}
80+
public const string Name = "ConsoleAppFrameworkSample";
81+
82+
public static ActivitySource Instance { get; } = new ActivitySource(Name);
7483
}
7584

76-
internal class NopFilter6(ConsoleAppFilter next)
77-
: ConsoleAppFilter(next)
85+
// Sample Activity filter
86+
internal class CommandTracingFilter(ConsoleAppFilter next) : ConsoleAppFilter(next)
7887
{
79-
public override Task InvokeAsync(ConsoleAppContext context, CancellationToken cancellationToken)
88+
public override async Task InvokeAsync(ConsoleAppContext context, CancellationToken cancellationToken)
8089
{
81-
Console.Write(6);
82-
return Next.InvokeAsync(context, cancellationToken);
90+
using var activity = ConsoleAppFrameworkSampleActivitySource.Instance.StartActivity("CommandStart");
91+
if (activity != null)
92+
{
93+
activity.SetTag("console_app.command_name", context.CommandName);
94+
activity.AddBaggage("console_app.command_args", string.Join(" ", context.EscapedArguments));
95+
}
96+
97+
try
98+
{
99+
await Next.InvokeAsync(context, cancellationToken);
100+
if (activity != null)
101+
{
102+
activity.SetStatus(ActivityStatusCode.Ok);
103+
}
104+
}
105+
catch (Exception ex)
106+
{
107+
if (activity != null)
108+
{
109+
if (ex is OperationCanceledException)
110+
{
111+
activity.SetStatus(ActivityStatusCode.Error, "Canceled");
112+
}
113+
else
114+
{
115+
activity.AddException(ex);
116+
activity.SetStatus(ActivityStatusCode.Error);
117+
}
118+
}
119+
throw;
120+
}
83121
}
84122
}

sandbox/GeneratorSandbox/Properties/launchSettings.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"profiles": {
33
"Default": {
44
"commandName": "Project",
5-
"commandLineArgs": "run --project foo.csproj -- --foo 100 --bar bazbaz"
5+
"commandLineArgs": ""
66
},
77
"ShowVersion": {
88
"commandName": "Project",

src/ConsoleAppFramework/ConsoleAppBaseCode.cs

Lines changed: 23 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -371,9 +371,9 @@ static void ShowVersion()
371371
372372
static partial void ShowHelp(int helpId);
373373
374-
static async Task RunWithFilterAsync(string commandName, string[] args, int commandDepth, int escapeIndex, ConsoleAppFilter invoker)
374+
static async Task RunWithFilterAsync(string commandName, string[] args, int commandDepth, int escapeIndex, ConsoleAppFilter invoker, CancellationToken cancellationToken)
375375
{
376-
using var posixSignalHandler = PosixSignalHandler.Register(Timeout);
376+
using var posixSignalHandler = PosixSignalHandler.Register(Timeout, cancellationToken);
377377
try
378378
{
379379
await Task.Run(() => invoker.InvokeAsync(new ConsoleAppContext(commandName, args, null, commandDepth, escapeIndex), posixSignalHandler.Token)).WaitAsync(posixSignalHandler.TimeoutToken);
@@ -411,16 +411,16 @@ sealed class PosixSignalHandler : IDisposable
411411
PosixSignalRegistration? sigQuit;
412412
PosixSignalRegistration? sigTerm;
413413
414-
PosixSignalHandler(TimeSpan timeout)
414+
PosixSignalHandler(TimeSpan timeout, CancellationToken cancellationToken)
415415
{
416-
this.cancellationTokenSource = new CancellationTokenSource();
416+
this.cancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
417417
this.timeoutCancellationTokenSource = new CancellationTokenSource();
418418
this.timeout = timeout;
419419
}
420420
421-
public static PosixSignalHandler Register(TimeSpan timeout)
421+
public static PosixSignalHandler Register(TimeSpan timeout, CancellationToken cancellationToken)
422422
{
423-
var handler = new PosixSignalHandler(timeout);
423+
var handler = new PosixSignalHandler(timeout, cancellationToken);
424424
425425
Action<PosixSignalContext> handleSignal = handler.HandlePosixSignal;
426426
@@ -443,6 +443,7 @@ public void Dispose()
443443
sigInt?.Dispose();
444444
sigQuit?.Dispose();
445445
sigTerm?.Dispose();
446+
cancellationTokenSource.Dispose();
446447
timeoutCancellationTokenSource.Dispose();
447448
}
448449
}
@@ -482,10 +483,10 @@ public void UseFilter<T>() where T : ConsoleAppFilter { }
482483
partial void AddCore(string commandName, Delegate command);
483484
484485
[MethodImpl(MethodImplOptions.AggressiveInlining)]
485-
partial void RunCore(string[] args);
486+
partial void RunCore(string[] args, CancellationToken cancellationToken);
486487
487488
[MethodImpl(MethodImplOptions.AggressiveInlining)]
488-
partial void RunAsyncCore(string[] args, ref Task result);
489+
partial void RunAsyncCore(string[] args, CancellationToken cancellationToken, ref Task result);
489490
490491
partial void BuildAndSetServiceProvider();
491492
@@ -546,15 +547,14 @@ internal static partial class ConsoleApp
546547
internal partial class ConsoleAppBuilder
547548
{
548549
public void Run(string[] args) => Run(args, true);
550+
public void Run(string[] args, CancellationToken cancellationToken) => Run(args, true, cancellationToken);
549551
550-
public Task RunAsync(string[] args) => RunAsync(args, true);
551-
552-
public void Run(string[] args, bool disposeService)
552+
public void Run(string[] args, bool disposeService, CancellationToken cancellationToken = default)
553553
{
554554
BuildAndSetServiceProvider();
555555
try
556556
{
557-
RunCore(args);
557+
RunCore(args, cancellationToken);
558558
}
559559
finally
560560
{
@@ -568,13 +568,16 @@ public void Run(string[] args, bool disposeService)
568568
}
569569
}
570570
571-
public async Task RunAsync(string[] args, bool disposeService)
571+
public Task RunAsync(string[] args) => RunAsync(args, true);
572+
public Task RunAsync(string[] args, CancellationToken cancellationToken) => RunAsync(args, true, cancellationToken);
573+
574+
public async Task RunAsync(string[] args, bool disposeService, CancellationToken cancellationToken = default)
572575
{
573576
BuildAndSetServiceProvider();
574577
try
575578
{
576579
Task? task = null;
577-
RunAsyncCore(args, ref task!);
580+
RunAsyncCore(args, cancellationToken, ref task!);
578581
if (task != null)
579582
{
580583
await task;
@@ -621,8 +624,9 @@ internal static partial class ConsoleApp
621624
internal partial class ConsoleAppBuilder
622625
{
623626
public void Run(string[] args) => Run(args, true, true, true);
627+
public void Run(string[] args, CancellationToken cancellationToken) => Run(args, true, true, true, cancellationToken);
624628
625-
public void Run(string[] args, bool startHost, bool stopHost, bool disposeService)
629+
public void Run(string[] args, bool startHost, bool stopHost, bool disposeService, CancellationToken cancellationToken = default)
626630
{
627631
BuildAndSetServiceProvider();
628632
Microsoft.Extensions.Hosting.IHost? host = ConsoleApp.ServiceProvider?.GetService(typeof(Microsoft.Extensions.Hosting.IHost)) as Microsoft.Extensions.Hosting.IHost;
@@ -632,7 +636,7 @@ public void Run(string[] args, bool startHost, bool stopHost, bool disposeServic
632636
{
633637
host?.StartAsync().GetAwaiter().GetResult();
634638
}
635-
RunCore(args);
639+
RunCore(args, cancellationToken);
636640
}
637641
finally
638642
{
@@ -651,8 +655,9 @@ public void Run(string[] args, bool startHost, bool stopHost, bool disposeServic
651655
}
652656
653657
public Task RunAsync(string[] args) => RunAsync(args, true, true, true);
658+
public Task RunAsync(string[] args, CancellationToken cancellationToken) => RunAsync(args, true, true, true, cancellationToken);
654659
655-
public async Task RunAsync(string[] args, bool startHost, bool stopHost, bool disposeService)
660+
public async Task RunAsync(string[] args, bool startHost, bool stopHost, bool disposeService, CancellationToken cancellationToken = default)
656661
{
657662
BuildAndSetServiceProvider();
658663
Microsoft.Extensions.Hosting.IHost? host = ConsoleApp.ServiceProvider?.GetService(typeof(Microsoft.Extensions.Hosting.IHost)) as Microsoft.Extensions.Hosting.IHost;
@@ -663,7 +668,7 @@ public async Task RunAsync(string[] args, bool startHost, bool stopHost, bool di
663668
await host?.StartAsync();
664669
}
665670
Task? task = null;
666-
RunAsyncCore(args, ref task!);
671+
RunAsyncCore(args, cancellationToken, ref task!);
667672
if (task != null)
668673
{
669674
await task;

0 commit comments

Comments
 (0)