From f6e8e49291878fee268d9e4a0f3948b47299a9fd Mon Sep 17 00:00:00 2001 From: Mayuki Sawatari Date: Wed, 21 Feb 2024 01:45:42 +0900 Subject: [PATCH 1/3] Fix stalls when class activation fails. --- src/Cocona/Hosting/CoconaHostedService.cs | 9 +++++--- .../Integration/CoconaAppRunTest.cs | 23 +++++++++++++++++++ 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/src/Cocona/Hosting/CoconaHostedService.cs b/src/Cocona/Hosting/CoconaHostedService.cs index 82a1a57..f51fbf8 100644 --- a/src/Cocona/Hosting/CoconaHostedService.cs +++ b/src/Cocona/Hosting/CoconaHostedService.cs @@ -67,13 +67,16 @@ private async Task ExecuteCoconaApplicationAsync(Task waitForApplicationStarted) // NOTE: Ignore OperationCanceledException that was thrown by non-user code. Environment.ExitCode = 0; } - catch (Exception) + catch (Exception ex) { + _console.Error.WriteLine(ex.ToString()); Environment.ExitCode = 1; throw; } - - _lifetime.StopApplication(); + finally + { + _lifetime.StopApplication(); + } } public async Task StopAsync(CancellationToken cancellationToken) diff --git a/test/Cocona.Test/Integration/CoconaAppRunTest.cs b/test/Cocona.Test/Integration/CoconaAppRunTest.cs index 35c7d93..1e3df85 100644 --- a/test/Cocona.Test/Integration/CoconaAppRunTest.cs +++ b/test/Cocona.Test/Integration/CoconaAppRunTest.cs @@ -989,4 +989,27 @@ class TestCommand_StopParsingOption public void A([Option]int a, [Option(StopParsingOptions = true)]string b, [Argument]string arg0, [Argument]string[] args) => Console.WriteLine($"A:{a}:{b}:{arg0}:{string.Join(",", args)}"); } + + + [Theory] + [InlineData(RunBuilderMode.CreateHostBuilder)] + [InlineData(RunBuilderMode.CreateBuilder)] + public void CoconaApp_Run_AbortOnActivationError(RunBuilderMode mode) + { + var (stdOut, stdErr, exitCode) = Run(mode, Array.Empty()); + exitCode.Should().Be(1); + stdErr.Should().StartWith("System.InvalidOperationException: Unable to resolve service"); + } + + class TestCommand_AbortOnActivationError + { + public TestCommand_AbortOnActivationError(Class1 class1) + { } + + public void A() + => Console.WriteLine($"Hello"); + + public class Class1 + { } + } } From 523812eab6e5ae99918bc48b98488ddc1d5bdddb Mon Sep 17 00:00:00 2001 From: Mayuki Sawatari Date: Wed, 6 Mar 2024 01:24:25 +0900 Subject: [PATCH 2/3] Fix Cocona.Lite --- src/Cocona.Lite/Lite/Hosting/CoconaLiteAppHost.cs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/Cocona.Lite/Lite/Hosting/CoconaLiteAppHost.cs b/src/Cocona.Lite/Lite/Hosting/CoconaLiteAppHost.cs index 0770531..8eb193e 100644 --- a/src/Cocona.Lite/Lite/Hosting/CoconaLiteAppHost.cs +++ b/src/Cocona.Lite/Lite/Hosting/CoconaLiteAppHost.cs @@ -1,3 +1,5 @@ +using System; +using Cocona.Application; using Cocona.Command; namespace Cocona.Lite.Hosting; @@ -21,6 +23,7 @@ public async Task RunAsync(CancellationToken cancellationToken) { var linkedCancellationToken = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, _cancellationTokenSource.Token); var bootstrapper = _serviceProvider.GetRequiredService(); + var console = _serviceProvider.GetRequiredService(); #pragma warning disable RS0030 // Do not used banned APIs Console.CancelKeyPress += OnCancelKeyPress; @@ -54,6 +57,13 @@ public async Task RunAsync(CancellationToken cancellationToken) // NOTE: Ignore OperationCanceledException that was thrown by non-user code. Environment.ExitCode = 130; } + catch (Exception ex) + { + console.Error.WriteLine(ex.ToString()); + Environment.ExitCode = 1; + // NOTE: Exception is suppressed here to match the behavior of Cocona. + //throw; + } _waitForShutdown.Set(); From 11b6f5b7432a0c876bda4627da0f907c01a46f04 Mon Sep 17 00:00:00 2001 From: Mayuki Sawatari Date: Wed, 6 Mar 2024 01:36:39 +0900 Subject: [PATCH 3/3] Prevent exception propagation to host --- src/Cocona.Lite/Lite/Hosting/CoconaLiteAppHost.cs | 2 -- src/Cocona/Hosting/CoconaHostedService.cs | 1 - 2 files changed, 3 deletions(-) diff --git a/src/Cocona.Lite/Lite/Hosting/CoconaLiteAppHost.cs b/src/Cocona.Lite/Lite/Hosting/CoconaLiteAppHost.cs index 8eb193e..1a33581 100644 --- a/src/Cocona.Lite/Lite/Hosting/CoconaLiteAppHost.cs +++ b/src/Cocona.Lite/Lite/Hosting/CoconaLiteAppHost.cs @@ -61,8 +61,6 @@ public async Task RunAsync(CancellationToken cancellationToken) { console.Error.WriteLine(ex.ToString()); Environment.ExitCode = 1; - // NOTE: Exception is suppressed here to match the behavior of Cocona. - //throw; } _waitForShutdown.Set(); diff --git a/src/Cocona/Hosting/CoconaHostedService.cs b/src/Cocona/Hosting/CoconaHostedService.cs index f51fbf8..6e9b154 100644 --- a/src/Cocona/Hosting/CoconaHostedService.cs +++ b/src/Cocona/Hosting/CoconaHostedService.cs @@ -71,7 +71,6 @@ private async Task ExecuteCoconaApplicationAsync(Task waitForApplicationStarted) { _console.Error.WriteLine(ex.ToString()); Environment.ExitCode = 1; - throw; } finally {