Skip to content

Commit

Permalink
feat(app): move app init logic outside of LifecycleService to use els…
Browse files Browse the repository at this point in the history
…ewhere
  • Loading branch information
SonicGD committed Dec 6, 2023
1 parent d157119 commit 6da3985
Show file tree
Hide file tree
Showing 4 changed files with 154 additions and 134 deletions.
131 changes: 131 additions & 0 deletions src/Sitko.Core.App/ApplicationLifecycle.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Serilog;

namespace Sitko.Core.App;

public class ApplicationLifecycle(
IApplicationContext context,
IServiceProvider provider,
IEnumerable<ApplicationModuleRegistration> applicationModuleRegistrations,
ILogger<ApplicationLifecycle> logger)
: IApplicationLifecycle
{
private readonly IReadOnlyList<ApplicationModuleRegistration> enabledModules =
ModulesHelper.GetEnabledModuleRegistrations(context, applicationModuleRegistrations);

public async Task StartingAsync(CancellationToken cancellationToken)
{
await using var scope = provider.CreateAsyncScope();

foreach (var enabledModule in enabledModules)
{
var shouldContinue = await enabledModule.GetInstance()
.OnBeforeRunAsync(context, scope.ServiceProvider);
if (!shouldContinue)
{
Environment.Exit(0);
return;
}
}

logger.LogInformation("Check required modules");
var modulesCheckSuccess = true;
foreach (var registration in enabledModules)
{
var result =
registration.CheckRequiredModules(context,
enabledModules.Select(r => r.Type).ToArray());
if (!result.isSuccess)
{
foreach (var missingModule in result.missingModules)
{
Log.Information("Required module {MissingModule} for module {Type} is not registered",
missingModule, registration.Type);
}

modulesCheckSuccess = false;
}
}

if (!modulesCheckSuccess)
{
throw new InvalidOperationException("Check required modules failed");
}

logger.LogInformation("Init modules");

foreach (var configurationModule in enabledModules.Select(module => module.GetInstance())
.OfType<IConfigurationModule>())
{
configurationModule.CheckConfiguration(context, scope.ServiceProvider);
}

foreach (var registration in enabledModules)
{
logger.LogInformation("Init module {Module}", registration.Type);
await registration.InitAsync(context, scope.ServiceProvider);
}

foreach (var enabledModule in enabledModules)
{
var shouldContinue =
await enabledModule.GetInstance().OnAfterRunAsync(context, scope.ServiceProvider);
if (!shouldContinue)
{
Environment.Exit(0);
}
}
}

public async Task StartedAsync(CancellationToken cancellationToken)
{
foreach (var moduleRegistration in enabledModules)
{
try
{
await moduleRegistration.ApplicationStarted(context, provider);
}
catch (Exception ex)
{
logger.LogError(ex, "Error on application started hook in module {Module}: {ErrorText}",
moduleRegistration.Type,
ex.ToString());
}
}
}

public async Task StoppingAsync(CancellationToken cancellationToken)
{
foreach (var moduleRegistration in enabledModules)
{
try
{
await moduleRegistration.ApplicationStopping(context, provider);
}
catch (Exception ex)
{
logger.LogError(ex, "Error on application stopping hook in module {Module}: {ErrorText}",
moduleRegistration.Type,
ex.ToString());
}
}
}

public async Task StoppedAsync(CancellationToken cancellationToken)
{
foreach (var moduleRegistration in enabledModules)
{
try
{
await moduleRegistration.ApplicationStopped(context, provider);
}
catch (Exception ex)
{
logger.LogError(ex, "Error on application stopped hook in module {Module}: {ErrorText}",
moduleRegistration.Type,
ex.ToString());
}
}
}
}
144 changes: 10 additions & 134 deletions src/Sitko.Core.App/HostedLifecycleService.cs
Original file line number Diff line number Diff line change
@@ -1,146 +1,22 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Serilog;
using Sitko.Core.App.Logging;
using Microsoft.Extensions.Hosting;

namespace Sitko.Core.App;

internal class HostedLifecycleService : IHostedLifecycleService
internal class HostedLifecycleService(IApplicationLifecycle lifecycle) : IHostedLifecycleService
{
private readonly ILogger<HostedLifecycleService> logger;
private readonly IApplicationContext applicationContext;
private readonly IServiceProvider serviceProvider;


private readonly IReadOnlyList<ApplicationModuleRegistration> enabledModules;

public HostedLifecycleService(ILogger<HostedLifecycleService> logger, IApplicationContext applicationContext,
IServiceProvider serviceProvider, IEnumerable<ApplicationModuleRegistration> applicationModuleRegistrations)
{
this.logger = logger;
this.applicationContext = applicationContext;
this.serviceProvider = serviceProvider;
enabledModules =
ModulesHelper.GetEnabledModuleRegistrations(applicationContext, applicationModuleRegistrations);
}

public Task StartAsync(CancellationToken cancellationToken) => Task.CompletedTask;

public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask;

public async Task StartingAsync(CancellationToken cancellationToken)
{
await using var scope = serviceProvider.CreateAsyncScope();

foreach (var enabledModule in enabledModules)
{
var shouldContinue = await enabledModule.GetInstance()
.OnBeforeRunAsync(applicationContext, scope.ServiceProvider);
if (!shouldContinue)
{
Environment.Exit(0);
return;
}
}

logger.LogInformation("Check required modules");
var modulesCheckSuccess = true;
foreach (var registration in enabledModules)
{
var result =
registration.CheckRequiredModules(applicationContext,
enabledModules.Select(r => r.Type).ToArray());
if (!result.isSuccess)
{
foreach (var missingModule in result.missingModules)
{
Log.Information(
$"Required module {missingModule} for module {registration.Type} is not registered");
}

modulesCheckSuccess = false;
}
}

if (!modulesCheckSuccess)
{
throw new InvalidOperationException("Check required modules failed");
}

logger.LogInformation("Init modules");

foreach (var configurationModule in enabledModules.Select(module => module.GetInstance())
.OfType<IConfigurationModule>())
{
configurationModule.CheckConfiguration(applicationContext, scope.ServiceProvider);
}

foreach (var registration in enabledModules)
{
logger.LogInformation("Init module {Module}", registration.Type);
await registration.InitAsync(applicationContext, scope.ServiceProvider);
}

foreach (var enabledModule in enabledModules)
{
var shouldContinue =
await enabledModule.GetInstance().OnAfterRunAsync(applicationContext, scope.ServiceProvider);
if (!shouldContinue)
{
Environment.Exit(0);
}
}
}
public Task StartingAsync(CancellationToken cancellationToken) =>
lifecycle.StartingAsync(cancellationToken);

public async Task StartedAsync(CancellationToken cancellationToken)
{
foreach (var moduleRegistration in enabledModules)
{
try
{
await moduleRegistration.ApplicationStarted(applicationContext, serviceProvider);
}
catch (Exception ex)
{
logger.LogError(ex, "Error on application started hook in module {Module}: {ErrorText}",
moduleRegistration.Type,
ex.ToString());
}
}
}
public Task StartedAsync(CancellationToken cancellationToken) =>
lifecycle.StartedAsync(cancellationToken);

public async Task StoppingAsync(CancellationToken cancellationToken)
{
foreach (var moduleRegistration in enabledModules)
{
try
{
await moduleRegistration.ApplicationStopping(applicationContext, serviceProvider);
}
catch (Exception ex)
{
logger.LogError(ex, "Error on application stopping hook in module {Module}: {ErrorText}",
moduleRegistration.Type,
ex.ToString());
}
}
}
public Task StoppingAsync(CancellationToken cancellationToken) =>
lifecycle.StoppingAsync(cancellationToken);

public async Task StoppedAsync(CancellationToken cancellationToken)
{
foreach (var moduleRegistration in enabledModules)
{
try
{
await moduleRegistration.ApplicationStopped(applicationContext, serviceProvider);
}
catch (Exception ex)
{
logger.LogError(ex, "Error on application stopped hook in module {Module}: {ErrorText}",
moduleRegistration.Type,
ex.ToString());
}
}
}
public Task StoppedAsync(CancellationToken cancellationToken) =>
lifecycle.StoppedAsync(cancellationToken);
}
12 changes: 12 additions & 0 deletions src/Sitko.Core.App/IApplicationLifecycle.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
namespace Sitko.Core.App;

public interface IApplicationLifecycle
{
Task StartingAsync(CancellationToken cancellationToken);

Task StartedAsync(CancellationToken cancellationToken);

Task StoppingAsync(CancellationToken cancellationToken);

Task StoppedAsync(CancellationToken cancellationToken);
}
1 change: 1 addition & 0 deletions src/Sitko.Core.App/SitkoCoreBaseApplicationBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ private void Init()
Services.AddTransient<IScheduler, Scheduler>();
Services.AddFluentValidationExtensions();
Services.AddTransient(typeof(ILocalizationProvider<>), typeof(LocalizationProvider<>));
Services.AddSingleton<IApplicationLifecycle, ApplicationLifecycle>(); // только Hosted? Проверить для Wasm
Services.AddHostedService<HostedLifecycleService>(); // только Hosted? Проверить для Wasm
}

Expand Down

0 comments on commit 6da3985

Please sign in to comment.