Skip to content

Commit

Permalink
Add MoryxService to handle closing the console window.
Browse files Browse the repository at this point in the history
Add extension method to KernelServiceCollectionExtensions to use the MoryxService.
Add dependency to Microsoft.Extensions.Hosting to make background services available.
  • Loading branch information
andreniggemann committed Nov 23, 2023
1 parent 684698a commit 9b34863
Show file tree
Hide file tree
Showing 4 changed files with 92 additions and 1 deletion.
1 change: 1 addition & 0 deletions Directory.Build.targets
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
<PackageReference Update="Microsoft.Extensions.Logging" Version="$(dotnetVersion)" />
<PackageReference Update="Microsoft.Extensions.Configuration.Json" Version="$(dotnetVersion)" />
<PackageReference Update="Microsoft.Extensions.Configuration.FileExtensions" Version="$(dotnetVersion)" />
<PackageReference Update="Microsoft.Extensions.Hosting" Version="$(dotnetVersion)" />
<PackageReference Update="Microsoft.Data.Sqlite" Version="$(dotnetVersion)" />

<PackageReference Update="Microsoft.EntityFrameworkCore" Version="$(efCoreVersion)" />
Expand Down
9 changes: 9 additions & 0 deletions src/Moryx.Runtime.Kernel/KernelServiceCollectionExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,15 @@ public static void AddMoryxModules(this IServiceCollection serviceCollection)
}
}

/// <summary>
/// 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.
/// </summary>
public static void AddMoryxService(this IServiceCollection serviceCollection)
{
serviceCollection.AddHostedService<MoryxService>();
}

/// <summary>
/// Use the moryx config manager
/// </summary>
Expand Down
2 changes: 1 addition & 1 deletion src/Moryx.Runtime.Kernel/Moryx.Runtime.Kernel.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,13 @@
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Configuration.FileExtensions" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" />
<PackageReference Include="Microsoft.Extensions.Hosting" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\Moryx\Moryx.csproj" />
<ProjectReference Include="..\Moryx.Container\Moryx.Container.csproj" />
<ProjectReference Include="..\Moryx.Runtime\Moryx.Runtime.csproj" />
</ItemGroup>

</Project>

81 changes: 81 additions & 0 deletions src/Moryx.Runtime.Kernel/MoryxService.cs
Original file line number Diff line number Diff line change
@@ -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<MoryxService> 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
}

/// <summary>
/// Callback that is called when a console event is raised.
/// </summary>
/// <param name="ctrlType"></param>
/// <returns></returns>
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<MoryxService> 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);
}
}
}

0 comments on commit 9b34863

Please sign in to comment.