# 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 `ActorRegistry` for 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:

```csharp
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:

```csharp
// 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:

```json
// 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"
  }
}
```

```csharp
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:

```csharp
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.):

```csharp
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:

1. Loggers
2. Remoting
3. Clustering (depends on Remoting)
4. Persistence
5. Distributed Data
6. Singletons and Singleton Proxies (depend on Clustering)
7. 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>
