Files
scadalink-design/AkkaDotNet/13-Discovery.md
Joseph Doherty de636b908b Add Akka.NET reference documentation
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.
2026-03-16 09:08:17 -04:00

4.4 KiB

13 — Discovery (Akka.Discovery)

Overview

Akka.Discovery provides a pluggable service discovery API that allows cluster nodes to find each other dynamically. It supports multiple backends: configuration-based (static), Azure Table Storage, AWS EC2, Kubernetes DNS, and more. Discovery is used by Akka.Management's Cluster Bootstrap to automate cluster formation.

In the SCADA system's 2-node topology with static IPs, Discovery's dynamic capabilities are largely unnecessary — static seed nodes work well. However, understanding Discovery is valuable for future-proofing and for sites that may use DHCP or containerized deployments.

When to Use

  • If site deployments use DHCP or dynamic IP assignment (uncommon in industrial environments but possible)
  • If the system is ever deployed in containers (Docker on Windows Server)
  • For sites where node addresses may change due to infrastructure migration

When Not to Use

  • In the current architecture with static IPs/hostnames — static seed nodes in the Cluster configuration are simpler and more predictable
  • For equipment discovery (finding machines on the network) — Akka.Discovery is for finding cluster nodes, not industrial equipment

Design Decisions for the SCADA System

Current Recommendation: Static Seed Nodes

For fixed 2-node deployments on Windows Server with known hostnames, static seed nodes (configured in 03-Cluster.md) are the simplest and most reliable approach. No Discovery plugin is needed.

Future Option: Config-Based Discovery

If the system needs a Discovery mechanism without external dependencies, use the built-in configuration-based discovery as a stepping stone:

akka.discovery {
  method = config
  config {
    services {
      scada-cluster {
        endpoints = [
          "nodeA.scada.local:4053",
          "nodeB.scada.local:4053"
        ]
      }
    }
  }
}

This is functionally equivalent to static seed nodes but uses the Discovery API, making it easier to swap to a dynamic provider later.

Future Option: Custom Discovery Provider

For sites with a central configuration management system (e.g., a site database that tracks which machines run the SCADA software), a custom Discovery provider could query that system to find cluster nodes:

public class SiteDbDiscovery : ServiceDiscovery
{
    public override Task<Resolved> Lookup(Lookup lookup, TimeSpan resolveTimeout)
    {
        // Query site database for SCADA node addresses
        var nodes = _siteDb.GetScadaNodes();
        var targets = nodes.Select(n => new ResolvedTarget(n.Hostname, n.Port)).ToList();
        return Task.FromResult(new Resolved(lookup.ServiceName, targets));
    }
}

Common Patterns

Discovery + Cluster Bootstrap

If Discovery is adopted, pair it with Akka.Management's Cluster Bootstrap (see 14-Management.md):

akkaBuilder
    .WithAkkaManagement(port: 8558)
    .WithClusterBootstrap(
        serviceName: "scada-cluster",
        requiredContactPoints: 2);

Fallback Chain

Aggregate Discovery allows chaining multiple discovery methods with fallback:

akka.discovery {
  method = aggregate
  aggregate {
    discovery-methods = ["custom-site-db", "config"]
  }
}

Anti-Patterns

Using Discovery for a 2-Node Static Deployment

Adding Discovery and Cluster Bootstrap to a fixed 2-node deployment with known addresses adds complexity without benefit. The Discovery plugin, Management HTTP endpoint, and Bootstrap coordination all introduce additional failure points.

Confusing Node Discovery with Equipment Discovery

Akka.Discovery finds Akka.NET cluster nodes. It does not discover industrial equipment on the network. OPC-UA has its own discovery mechanism (OPC-UA Discovery Server); the custom protocol presumably has its own registration or configuration approach.

Configuration Guidance

For the current architecture, no Discovery configuration is needed. If adopted in the future:

akka.discovery {
  method = config  # Or "azure", "aws", "kubernetes", etc.
  config {
    services {
      scada-cluster {
        endpoints = [
          "nodeA.scada.local:4053",
          "nodeB.scada.local:4053"
        ]
      }
    }
  }
}

References