Files
scadalink-design/Component-Host.md
Joseph Doherty 409cc62309 Verify component designs against Akka.NET best practices documentation
Cluster Infrastructure: add min-nr-of-members=1 requirement for single-node
operation after failover. Add graceful shutdown / CoordinatedShutdown section
for fast singleton handover during planned maintenance.

Site Runtime: add explicit supervision strategies per actor type (Resume for
coordinators, Stop for short-lived execution actors). Stagger Instance Actor
startup to prevent reconnection storms. Add Tell-vs-Ask usage guidance per
Akka.NET best practices (Tell for hot path, Ask for system boundaries only).

Data Connection Layer: add Connection Actor Model section documenting the
Become/Stash pattern for connection lifecycle state machine.

Health Monitoring: add dead letter count as a monitored metric.

Host: add REQ-HOST-8a for dead letter monitoring (subscribe to EventStream,
log at Warning level, report as health metric).
2026-03-16 09:12:36 -04:00

9.3 KiB
Raw Blame History

Component: Host

Purpose

The Host component is the single deployable executable for the entire ScadaLink system. The same binary runs on every node — central and site alike. The node's role is determined entirely by configuration (appsettings.json), not by which binary is deployed. On central nodes the Host additionally bootstraps ASP.NET Core to serve the Central UI and Inbound API web endpoints.

Location

All nodes (central and site).

Responsibilities

  • Serve as the single entry point (Program.cs) for the ScadaLink process.
  • Read and validate node configuration at startup before any actor system is created.
  • Register the correct set of component services and actors based on the configured node role.
  • Bootstrap the Akka.NET actor system with Remoting, Clustering, Persistence, and split-brain resolution via Akka.Hosting.
  • Host ASP.NET Core web endpoints on central nodes only.
  • Configure structured logging (Serilog) with environment-specific enrichment.
  • Support running as a Windows Service in production and as a console application during development.
  • Perform graceful shutdown via Akka.NET CoordinatedShutdown when the service is stopped.

Requirements

REQ-HOST-1: Single Binary Deployment

The same compiled binary must be deployable to both central and site nodes. The node's role (Central or Site) is determined solely by configuration values in appsettings.json (or environment-specific overrides). There must be no separate build targets, projects, or conditional compilation symbols for central vs. site.

REQ-HOST-2: Role-Based Service Registration

At startup the Host must inspect the configured node role and register only the component services appropriate for that role:

  • Shared (both Central and Site): ClusterInfrastructure, Communication, HealthMonitoring, ExternalSystemGateway, NotificationService.
  • Central only: TemplateEngine, DeploymentManager, Security, AuditLogging, CentralUI, InboundAPI.
  • Site only: SiteRuntime, DataConnectionLayer, StoreAndForward, SiteEventLogging.

Components not applicable to the current role must not be registered in the DI container or the Akka.NET actor system.

REQ-HOST-3: Configuration Binding

The Host must bind configuration sections from appsettings.json to strongly-typed options classes using the .NET Options pattern:

  • ScadaLink:Node section bound to NodeConfiguration (Role, NodeHostname, SiteId, RemotingPort).
  • ScadaLink:Cluster section bound to ClusterConfiguration (SeedNodes, SplitBrainResolverStrategy, StableAfter).
  • ScadaLink:Database section bound to DatabaseConfiguration (Central: ConfigurationDb, MachineDataDb connection strings; Site: SQLite paths).

REQ-HOST-4: Startup Validation

Before the Akka.NET actor system is created, the Host must validate all required configuration values and fail fast with a clear error message if any are missing or invalid. Validation rules include:

  • NodeConfiguration.Role must be a valid NodeRole value.
  • NodeConfiguration.NodeHostname must not be null or empty.
  • NodeConfiguration.RemotingPort must be in valid port range (165535).
  • Site nodes must have a non-empty SiteId.
  • Central nodes must have non-empty ConfigurationDb and MachineDataDb connection strings.
  • Site nodes must have non-empty SQLite path values.
  • At least two seed nodes must be configured.

REQ-HOST-4a: Readiness Gating

On central nodes, the ASP.NET Core web endpoints (Central UI, Inbound API) must not accept traffic until the node is fully operational:

  • Akka.NET cluster membership is established.
  • Database connectivity (MS SQL) is verified.
  • Required cluster singletons are running (if applicable).

A standard ASP.NET Core health check endpoint (/health/ready) reports readiness status. The load balancer uses this endpoint to determine when to route traffic to the node. During startup or failover, the node returns 503 Service Unavailable until ready.

REQ-HOST-5: Windows Service Hosting

The Host must support running as a Windows Service via UseWindowsService(). When launched outside of a Windows Service context (e.g., during development), it must run as a standard console application. No code changes or conditional compilation are required to switch between the two modes.

REQ-HOST-6: Akka.NET Bootstrap

The Host must configure the Akka.NET actor system using Akka.Hosting with:

  • Remoting: Configured with the node's hostname and port from NodeConfiguration.
  • Clustering: Configured with seed nodes and the node's cluster role from configuration.
  • Persistence: Configured with the appropriate journal and snapshot store (SQL for central, SQLite for site).
  • Split-Brain Resolver: Configured with the strategy and stable-after duration from ClusterConfiguration.
  • Actor registration: Each component's actors registered via its AddXxxActors() extension method, conditional on the node's role.

REQ-HOST-7: ASP.NET Web Endpoints (Central Only)

On central nodes, the Host must use WebApplication.CreateBuilder to produce a full ASP.NET Core host with Kestrel, and must map web endpoints for:

  • Central UI (via MapCentralUI() extension method).
  • Inbound API (via MapInboundAPI() extension method).

On site nodes, the Host must use Host.CreateDefaultBuilder to produce a generic IHostnot a WebApplication. This ensures no Kestrel server is started, no HTTP port is opened, and no web endpoint or middleware pipeline is configured. Site nodes are headless and must never accept inbound HTTP connections.

REQ-HOST-8: Structured Logging

The Host must configure Serilog as the logging provider with:

  • Configuration-driven sink setup (console and file sinks at minimum).
  • Automatic enrichment of every log entry with SiteId, NodeHostname, and NodeRole properties sourced from NodeConfiguration.
  • Structured (machine-parseable) output format.

REQ-HOST-8a: Dead Letter Monitoring

The Host must subscribe to the Akka.NET DeadLetter event stream and log dead letters at Warning level. Dead letters indicate messages sent to actors that no longer exist — a common symptom of failover timing issues, stale actor references, or race conditions during instance lifecycle transitions. The dead letter count is reported as a health metric (see Health Monitoring).

REQ-HOST-9: Graceful Shutdown

When the Host process receives a stop signal (Windows Service stop, Ctrl+C, or SIGTERM), it must trigger Akka.NET CoordinatedShutdown to allow actors to drain in-flight work before the process exits. The Host must not call Environment.Exit() or forcibly terminate the actor system without coordinated shutdown.

REQ-HOST-10: Extension Method Convention

Each component library must expose its services to the Host via a consistent set of extension methods:

  • IServiceCollection.AddXxx() — registers the component's DI services.
  • AkkaConfigurationBuilder.AddXxxActors() — registers the component's actors with the Akka.NET actor system (for components that have actors).
  • WebApplication.MapXxx() — maps the component's web endpoints (only for CentralUI and InboundAPI).

The Host's Program.cs calls these extension methods; the component libraries own the registration logic. This keeps the Host thin and each component self-contained.


Component Registration Matrix

Component Central Site DI (AddXxx) Actors (AddXxxActors) Endpoints (MapXxx)
ClusterInfrastructure Yes Yes Yes Yes No
Communication Yes Yes Yes Yes No
HealthMonitoring Yes Yes Yes Yes No
ExternalSystemGateway Yes Yes Yes Yes No
NotificationService Yes Yes Yes Yes No
TemplateEngine Yes No Yes Yes No
DeploymentManager Yes No Yes Yes No
Security Yes No Yes Yes No
CentralUI Yes No Yes No Yes
InboundAPI Yes No Yes No Yes
SiteRuntime No Yes Yes Yes No
DataConnectionLayer No Yes Yes Yes No
StoreAndForward No Yes Yes Yes No
SiteEventLogging No Yes Yes Yes No
ConfigurationDatabase Yes No Yes No No

Dependencies

  • All 15 component libraries: The Host references every component project to call their extension methods.
  • Akka.Hosting: For AddAkka() and the hosting configuration builder.
  • Akka.Remote.Hosting, Akka.Cluster.Hosting, Akka.Persistence.Hosting: For Akka subsystem configuration.
  • Serilog.AspNetCore: For structured logging integration.
  • Microsoft.Extensions.Hosting.WindowsServices: For Windows Service support.
  • ASP.NET Core (central only): For web endpoint hosting.

Interactions

  • All components: The Host is the composition root — it wires every component into the DI container and actor system.
  • Configuration Database: The Host registers the DbContext and wires repository implementations to their interfaces. In development, triggers auto-migration; in production, validates schema version.
  • ClusterInfrastructure: The Host configures the underlying Akka.NET cluster that ClusterInfrastructure manages at runtime.
  • CentralUI / InboundAPI: The Host maps their web endpoints into the ASP.NET Core pipeline on central nodes.
  • HealthMonitoring: The Host's startup validation and logging configuration provide the foundation for health reporting.