Notes and documentation covering actors, remoting, clustering, persistence, streams, serialization, hosting, testing, and best practices for the Akka.NET framework used throughout the ScadaLink system.
6.8 KiB
11 — Akka.Hosting
Overview
Akka.Hosting is the recommended integration layer between Akka.NET and the Microsoft.Extensions.* ecosystem (Hosting, DependencyInjection, Configuration, Logging). It replaces the traditional HOCON-only configuration approach with a code-first, type-safe API and provides an ActorRegistry for injecting actor references into non-actor services.
In our SCADA system, Akka.Hosting is the entry point for bootstrapping the entire ActorSystem — configuring Remoting, Cluster, Singleton, Persistence, and all other modules through a fluent C# API that integrates with the standard .NET Generic Host.
When to Use
- Always — Akka.Hosting should be the primary way to configure and start Akka.NET in any new .NET 10 application
- Configuring all Akka.NET modules (Remoting, Cluster, Persistence, etc.) in code rather than HOCON files
- Registering top-level actors in the
ActorRegistryfor injection into ASP.NET controllers, Windows Services, or other DI consumers - Managing ActorSystem lifecycle tied to the .NET host lifecycle
When Not to Use
- There are no scenarios where you should avoid Akka.Hosting in new projects on .NET 6+
- Legacy projects on older .NET may need the traditional HOCON approach if they cannot adopt
Microsoft.Extensions.Hosting
Design Decisions for the SCADA System
Windows Service Host
The SCADA application runs as a Windows Service using the .NET Generic Host:
var builder = Host.CreateApplicationBuilder(args);
builder.Services.AddAkka("scada-system", (akkaBuilder, sp) =>
{
var siteConfig = sp.GetRequiredService<SiteConfiguration>();
akkaBuilder
.ConfigureLoggers(loggers =>
{
loggers.LogLevel = Akka.Event.LogLevel.InfoLevel;
loggers.AddLoggerFactory(); // Bridge to Microsoft.Extensions.Logging
})
.WithRemoting(options =>
{
options.Hostname = "0.0.0.0";
options.PublicHostname = siteConfig.NodeHostname;
options.Port = 4053;
})
.WithClustering(new ClusterOptions
{
Roles = new[] { "scada-node" },
SeedNodes = siteConfig.SeedNodes
})
.WithSingleton<DeviceManagerActor>("device-manager",
(system, registry, resolver) => resolver.Props<DeviceManagerActor>(),
new ClusterSingletonOptions { Role = "scada-node" })
.WithSingletonProxy<DeviceManagerActor>("device-manager",
new ClusterSingletonProxyOptions { Role = "scada-node" })
.WithDistributedData()
.WithActors((system, registry, resolver) =>
{
var healthActor = system.ActorOf(
resolver.Props<ClusterHealthActor>(), "cluster-health");
registry.Register<ClusterHealthActor>(healthActor);
});
});
var host = builder.Build();
await host.RunAsync();
ActorRegistry for DI Integration
The ActorRegistry stores named IActorRef instances that can be injected into non-actor services:
// Registering actors
registry.Register<DeviceManagerActor>(deviceManagerRef);
registry.Register<ClusterHealthActor>(healthActorRef);
// Consuming in a Windows Service health check endpoint
public class HealthCheckService : IHostedService
{
private readonly IRequiredActor<ClusterHealthActor> _healthActor;
public HealthCheckService(IRequiredActor<ClusterHealthActor> healthActor)
{
_healthActor = healthActor;
}
public async Task<HealthStatus> CheckHealthAsync()
{
var actorRef = await _healthActor.GetAsync();
var status = await actorRef.Ask<ClusterHealthStatus>(new GetHealth(), TimeSpan.FromSeconds(5));
return status.IsHealthy ? HealthStatus.Healthy : HealthStatus.Unhealthy;
}
}
Site-Specific Configuration
Use Microsoft.Extensions.Configuration (appsettings.json, environment variables) for site-specific values (hostnames, seed nodes, device lists). Inject these into the Akka configuration:
// appsettings.json
{
"ScadaSite": {
"NodeHostname": "nodeA.scada.local",
"SeedNodes": [
"akka.tcp://scada-system@nodeA.scada.local:4053",
"akka.tcp://scada-system@nodeB.scada.local:4053"
],
"DeviceConfigPath": "C:\\ProgramData\\SCADA\\devices.json"
}
}
builder.Services.Configure<SiteConfiguration>(
builder.Configuration.GetSection("ScadaSite"));
Common Patterns
Combining HOCON and Hosting
For module-specific settings not yet covered by Hosting APIs, you can mix HOCON with code-first configuration:
akkaBuilder.AddHocon(ConfigurationFactory.ParseString(@"
akka.cluster.split-brain-resolver {
active-strategy = keep-oldest
keep-oldest.down-if-alone = on
stable-after = 15s
}
"), HoconAddMode.Prepend);
Logging Bridge
Bridge Akka.NET's internal logging to Microsoft.Extensions.Logging so all logs go through the same pipeline (Serilog, NLog, etc.):
akkaBuilder.ConfigureLoggers(loggers =>
{
loggers.ClearLoggers();
loggers.AddLoggerFactory();
});
Coordinated Shutdown Integration
Akka.Hosting automatically ties CoordinatedShutdown to the host's lifetime. When the Windows Service stops, the ActorSystem leaves the cluster gracefully and shuts down. No additional configuration is needed.
Anti-Patterns
Bypassing Hosting to Create ActorSystem Manually
Do not create ActorSystem.Create() alongside Akka.Hosting. This creates a second, unmanaged ActorSystem. Always use AddAkka() on the service collection.
Registering Actors That Don't Exist Yet
The ActorRegistry resolves asynchronously (GetAsync()), but registering an actor reference that is never created will cause consumers to hang indefinitely. Always register actors in the WithActors callback where they are created.
Hardcoding Configuration
Do not hardcode hostnames, ports, or seed nodes in the AddAkka configuration. Use Microsoft.Extensions.Configuration so that each site's deployment can override these values via appsettings.json or environment variables.
Configuration Guidance
NuGet Packages
Akka.Hosting
Akka.Remote.Hosting
Akka.Cluster.Hosting (includes Sharding, Tools)
Akka.Persistence.Hosting
These Hosting packages replace the need to install the base packages separately — they include their dependencies.
Startup Order
Akka.Hosting initializes components in the order they are registered. Register in dependency order:
- Loggers
- Remoting
- Clustering (depends on Remoting)
- Persistence
- Distributed Data
- Singletons and Singleton Proxies (depend on Clustering)
- Application actors
References
- GitHub / Documentation: https://github.com/akkadotnet/Akka.Hosting
- Petabridge Blog: https://petabridge.com/blog/akkadotnet-hosting-aspnet/
- DI with Akka.NET: https://getakka.net/articles/actors/dependency-injection.html