Files
ScadaBridge/src/ZB.MOM.WW.ScadaBridge.DeploymentManager/ServiceCollectionExtensions.cs
T

81 lines
4.4 KiB
C#

using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Options;
using ZB.MOM.WW.ScadaBridge.Commons.Interfaces.Services;
using ZB.MOM.WW.ScadaBridge.Commons.Interfaces.Transport;
using ZB.MOM.WW.ScadaBridge.Commons.Types.Templates;
namespace ZB.MOM.WW.ScadaBridge.DeploymentManager;
public static class ServiceCollectionExtensions
{
/// <summary>
/// Configuration section that <see cref="DeploymentManagerOptions"/> is bound to.
/// The Host binds this section to <c>appsettings.json</c> (see
/// <c>Program.cs</c>); component libraries do not depend on
/// <c>IConfiguration</c> directly, consistent with the Options-pattern
/// convention enforced by <c>OptionsTests</c>.
/// </summary>
public const string OptionsSection = "ScadaBridge:DeploymentManager";
/// <summary>
/// Registers the Deployment Manager services. <see cref="DeploymentManagerOptions"/>
/// is registered via <see cref="OptionsServiceCollectionExtensions.AddOptions"/> so
/// <c>IOptions&lt;DeploymentManagerOptions&gt;</c> is always resolvable; the Host
/// binds <see cref="OptionsSection"/> to configuration so the operation-lock and
/// artifact-deployment timeouts are tunable via <c>appsettings.json</c>.
/// </summary>
/// <param name="services">The service collection to register into.</param>
/// <returns>The <paramref name="services"/> instance for chaining.</returns>
public static IServiceCollection AddDeploymentManager(this IServiceCollection services)
{
// Ensure the options class is always resolvable.
// The Host binds OptionsSection to appsettings.json; absent that binding
// the declared option-class defaults apply. Eager startup validation
// (arch-review 08 §1.5): ValidateOnStart makes a zero/negative timeout —
// which would fire a linked-CTS deadline immediately (or throw in the
// CancellationTokenSource ctor) — fail fast at boot with a clear,
// key-naming message. Applies even though defaults are code-configured.
services.AddOptions<DeploymentManagerOptions>().ValidateOnStart();
services.TryAddEnumerable(
ServiceDescriptor.Singleton<IValidateOptions<DeploymentManagerOptions>, DeploymentManagerOptionsValidator>());
services.AddSingleton<OperationLockManager>();
// Template/instance version watermark backing the flatten-session cache key
// and the staleness fast path. TryAdd because AddConfigurationDatabase
// registers the same singleton — whichever composition root runs first wins
// and both observe one instance.
services.TryAddSingleton<ITemplateGraphWatermark, TemplateGraphWatermark>();
// Push-based deployment-status notification. Registered
// as a singleton so the scoped DeploymentService and the Central UI's
// scoped Blazor page component share one instance — both run in the
// same central Host process. The deployment-status page subscribes to
// it instead of polling the database every 10 seconds.
services.AddSingleton<IDeploymentStatusNotifier, DeploymentStatusNotifier>();
services.AddScoped<IFlatteningPipeline, FlatteningPipeline>();
services.AddScoped<DeploymentService>();
services.AddScoped<ArtifactDeploymentService>();
// Expose the flattening pipeline's revision-hash computation
// to the Transport bundle importer through the Commons IStaleInstanceProbe
// seam, so a template overwrite can enumerate the deployed instances whose
// flattened config has drifted from their deployed snapshot. Scoped so it
// shares the per-request DbContext with the in-flight import.
services.AddScoped<IStaleInstanceProbe, StaleInstanceProbe>();
return services;
}
/// <summary>
/// Registers Deployment Manager Akka actor bindings. Actor creation is handled by the Host during actor system startup.
/// </summary>
/// <param name="services">The service collection to register into.</param>
/// <returns>The <paramref name="services"/> instance for chaining.</returns>
public static IServiceCollection AddDeploymentManagerActors(this IServiceCollection services)
{
// Akka actor registration is handled by Host component during actor system startup
return services;
}
}