From 7d64c352420ec9c7820ec3169764840b64a1d714 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niggemann=2C=20Andr=C3=A9=20=28n7md82=29?= Date: Thu, 23 Nov 2023 08:09:23 +0100 Subject: [PATCH 1/3] Add MoryxService to handle closing the console window. Add extension method to KernelServiceCollectionExtensions to use the MoryxService. Add dependency to Microsoft.Extensions.Hosting to make background services available. --- Directory.Build.targets | 1 + .../KernelServiceCollectionExtensions.cs | 9 +++ .../Moryx.Runtime.Kernel.csproj | 7 +- src/Moryx.Runtime.Kernel/MoryxService.cs | 81 +++++++++++++++++++ 4 files changed, 97 insertions(+), 1 deletion(-) create mode 100644 src/Moryx.Runtime.Kernel/MoryxService.cs diff --git a/Directory.Build.targets b/Directory.Build.targets index d12d3f6bd..61e496c59 100644 --- a/Directory.Build.targets +++ b/Directory.Build.targets @@ -34,6 +34,7 @@ + diff --git a/src/Moryx.Runtime.Kernel/KernelServiceCollectionExtensions.cs b/src/Moryx.Runtime.Kernel/KernelServiceCollectionExtensions.cs index 83bc5b833..4ca6b5931 100644 --- a/src/Moryx.Runtime.Kernel/KernelServiceCollectionExtensions.cs +++ b/src/Moryx.Runtime.Kernel/KernelServiceCollectionExtensions.cs @@ -74,6 +74,15 @@ public static void AddMoryxModules(this IServiceCollection serviceCollection) } } + /// + /// Register BackgroundService that controls that starts and stops the MORYX modules inside the lifetime of the host. + /// The MORYX Service can hook into the command line and gracefuly stop the modules when the user tries to close the window. + /// + public static void AddMoryxService(this IServiceCollection serviceCollection) + { + serviceCollection.AddHostedService(); + } + /// /// Use the moryx config manager /// diff --git a/src/Moryx.Runtime.Kernel/Moryx.Runtime.Kernel.csproj b/src/Moryx.Runtime.Kernel/Moryx.Runtime.Kernel.csproj index 054c7834f..207472286 100644 --- a/src/Moryx.Runtime.Kernel/Moryx.Runtime.Kernel.csproj +++ b/src/Moryx.Runtime.Kernel/Moryx.Runtime.Kernel.csproj @@ -7,11 +7,16 @@ MORYX;Kernel;Runtime;Server + + + + + + - \ No newline at end of file diff --git a/src/Moryx.Runtime.Kernel/MoryxService.cs b/src/Moryx.Runtime.Kernel/MoryxService.cs new file mode 100644 index 000000000..b020ec1a8 --- /dev/null +++ b/src/Moryx.Runtime.Kernel/MoryxService.cs @@ -0,0 +1,81 @@ +using Castle.Core.Logging; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; +using Moryx.Runtime.Modules; +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace Moryx.Runtime.Kernel +{ + internal class MoryxService : BackgroundService + { + private readonly IModuleManager moduleManager; + private readonly IHost lifeTime; + private readonly ILogger logger; + + // Console shutdown handling according to https://stackoverflow.com/questions/21751545/how-to-make-a-console-app-exit-gracefully-when-it-is-closed + [DllImport("Kernel32")] + public static extern bool SetConsoleCtrlHandler(HandlerRoutine Handler, bool Add); + + // A delegate type to be used as the handler routine + // for SetConsoleCtrlHandler. + public delegate bool HandlerRoutine(CtrlTypes CtrlType); + + // An enumerated type for the control messages + // sent to the handler routine. + public enum CtrlTypes + { + CTRL_C_EVENT = 0, + CTRL_BREAK_EVENT, + CTRL_CLOSE_EVENT, + CTRL_LOGOFF_EVENT = 5, + CTRL_SHUTDOWN_EVENT + } + + /// + /// Callback that is called when a console event is raised. + /// + /// + /// + private bool ConsoleCtrlCheck(CtrlTypes ctrlType) + { + // Stop the host and await shutdown. + lifeTime.StopAsync(TimeSpan.FromSeconds(100)).ContinueWith(task => + { + if (task.IsFaulted) + { + logger.LogError(task.Exception, "Received failure on shutdown."); + } + }).Wait(); + return true; + } + + public MoryxService(IModuleManager moduleManager, IHost lifetTime, ILogger logger) + { + this.moduleManager = moduleManager; + this.lifeTime = lifetTime; + this.logger = logger; + } + + public override async Task StartAsync(CancellationToken cancellationToken) + { + SetConsoleCtrlHandler(ConsoleCtrlCheck, true); + moduleManager.StartModules(); + await base.StartAsync(cancellationToken); + } + protected override Task ExecuteAsync(CancellationToken stoppingToken) + { + return Task.CompletedTask; + } + + public override async Task StopAsync(CancellationToken cancellationToken) + { + moduleManager.StopModules(); + await base.StopAsync(cancellationToken); + } + } +} From ff72cbdba74b59a402299ce636c4f62126ffbaad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andre=C2=B4=20Niggemann?= Date: Tue, 3 Sep 2024 14:59:26 +0200 Subject: [PATCH 2/3] Renamed to MoryxHost instead of Service. Add Platform check, so that it does not crash on other platforms. Add StateChanged event to enable other servicees to plug into the moryx lifecycle via the host. --- .../KernelServiceCollectionExtensions.cs | 2 +- .../{MoryxService.cs => MoryxHost.cs} | 38 +++++++++++++++---- 2 files changed, 31 insertions(+), 9 deletions(-) rename src/Moryx.Runtime.Kernel/{MoryxService.cs => MoryxHost.cs} (67%) diff --git a/src/Moryx.Runtime.Kernel/KernelServiceCollectionExtensions.cs b/src/Moryx.Runtime.Kernel/KernelServiceCollectionExtensions.cs index 4ca6b5931..8275f2db1 100644 --- a/src/Moryx.Runtime.Kernel/KernelServiceCollectionExtensions.cs +++ b/src/Moryx.Runtime.Kernel/KernelServiceCollectionExtensions.cs @@ -80,7 +80,7 @@ public static void AddMoryxModules(this IServiceCollection serviceCollection) /// public static void AddMoryxService(this IServiceCollection serviceCollection) { - serviceCollection.AddHostedService(); + serviceCollection.AddHostedService(); } /// diff --git a/src/Moryx.Runtime.Kernel/MoryxService.cs b/src/Moryx.Runtime.Kernel/MoryxHost.cs similarity index 67% rename from src/Moryx.Runtime.Kernel/MoryxService.cs rename to src/Moryx.Runtime.Kernel/MoryxHost.cs index b020ec1a8..16344b7e1 100644 --- a/src/Moryx.Runtime.Kernel/MoryxService.cs +++ b/src/Moryx.Runtime.Kernel/MoryxHost.cs @@ -1,21 +1,18 @@ -using Castle.Core.Logging; -using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using Moryx.Runtime.Modules; using System; -using System.Collections.Generic; using System.Runtime.InteropServices; -using System.Text; using System.Threading; using System.Threading.Tasks; namespace Moryx.Runtime.Kernel { - internal class MoryxService : BackgroundService + internal class MoryxHost : BackgroundService { private readonly IModuleManager moduleManager; private readonly IHost lifeTime; - private readonly ILogger logger; + private readonly ILogger logger; // Console shutdown handling according to https://stackoverflow.com/questions/21751545/how-to-make-a-console-app-exit-gracefully-when-it-is-closed [DllImport("Kernel32")] @@ -54,18 +51,39 @@ private bool ConsoleCtrlCheck(CtrlTypes ctrlType) return true; } - public MoryxService(IModuleManager moduleManager, IHost lifetTime, ILogger logger) + public MoryxHost(IModuleManager moduleManager, IHost lifetTime, ILogger logger) { this.moduleManager = moduleManager; this.lifeTime = lifetTime; this.logger = logger; } + public enum MoryxHostState { + NotStarted, + Starting, + Started, + Stopping, + Stopped + } + + public MoryxHostState State {get;private set;} + public event EventHandler StateChanged; + public override async Task StartAsync(CancellationToken cancellationToken) { - SetConsoleCtrlHandler(ConsoleCtrlCheck, true); + State = MoryxHostState.Starting; + StateChanged?.Invoke(this, State); + // Only register on windows, because the behavior is os specific + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + SetConsoleCtrlHandler(ConsoleCtrlCheck, true); + } moduleManager.StartModules(); + await base.StartAsync(cancellationToken); + + State = MoryxHostState.Started; + StateChanged?.Invoke(this, State); } protected override Task ExecuteAsync(CancellationToken stoppingToken) { @@ -74,8 +92,12 @@ protected override Task ExecuteAsync(CancellationToken stoppingToken) public override async Task StopAsync(CancellationToken cancellationToken) { + State = MoryxHostState.Stopping; + StateChanged?.Invoke(this, State); moduleManager.StopModules(); await base.StopAsync(cancellationToken); + State = MoryxHostState.Stopped; + StateChanged?.Invoke(this, State); } } } From b9e489cc63dac78af86592a87f76860ade7aee2e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andre=C2=B4=20Niggemann?= Date: Tue, 3 Sep 2024 17:52:46 +0200 Subject: [PATCH 3/3] Remove unnecessary dependencies --- src/Moryx.Runtime.Kernel/Moryx.Runtime.Kernel.csproj | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Moryx.Runtime.Kernel/Moryx.Runtime.Kernel.csproj b/src/Moryx.Runtime.Kernel/Moryx.Runtime.Kernel.csproj index 207472286..650956a63 100644 --- a/src/Moryx.Runtime.Kernel/Moryx.Runtime.Kernel.csproj +++ b/src/Moryx.Runtime.Kernel/Moryx.Runtime.Kernel.csproj @@ -8,8 +8,6 @@ - -