distribute/discovery/behaviour

Discovery behaviour contract for peer discovery.

This module defines the contract that discovery adapters must implement to provide peer discovery and membership tracking in the distribute library. Discovery adapters are responsible for finding peers, tracking membership state, and emitting membership events.

Design Philosophy

This behaviour follows distribute’s patterns:

Implementation Approaches

Adapters can be implemented as:

  1. Actor-based: Use gleam/otp/actor (recommended, see registry/actor)
  2. DNS-SRV: Query DNS for service records
  3. Kubernetes: Use K8s API for pod discovery
  4. Static: Fixed list of peers for simple deployments

Integration with distribute

Discovery adapters integrate with:

Example Implementation

See distribute/discovery/beam_adapter for a reference implementation.

Types

Errors that can occur during discovery operations.

Classification

  • Transient (retryable): SyncFailed, Timeout
  • Permanent (do not retry): InvalidConfiguration, PeerNotFound
pub type DiscoveryError {
  StartFailed(reason: String)
  StopFailed(reason: String)
  ShutdownTimeout(elapsed_ms: Int)
  SyncFailed(reason: String)
  PeerNotFound(peer: String)
  InvalidConfiguration(reason: String)
  Timeout(elapsed_ms: Int)
  SubscriptionFailed(reason: String)
}

Constructors

  • StartFailed(reason: String)

    Failed to start the discovery adapter

  • StopFailed(reason: String)

    Failed to stop the discovery adapter

  • ShutdownTimeout(elapsed_ms: Int)

    Shutdown timed out

  • SyncFailed(reason: String)

    Failed to sync with discovery backend

  • PeerNotFound(peer: String)

    Peer not found in current membership

  • InvalidConfiguration(reason: String)

    Invalid adapter configuration

  • Timeout(elapsed_ms: Int)

    Operation timed out

  • SubscriptionFailed(reason: String)

    Failed to create/manage subscription

Events emitted by discovery adapters.

Discovery adapters push events to subscribers when membership changes. Subscribers should process events quickly; heavy processing should be done asynchronously.

Variants

  • PeerUp: A new peer has been discovered and is available
  • PeerUpdate: A known peer’s metadata has changed
  • PeerDown: A peer has left or become unavailable
pub type DiscoveryEvent {
  PeerUp(peer: String, metadata: dict.Dict(String, String))
  PeerUpdate(peer: String, metadata: dict.Dict(String, String))
  PeerDown(peer: String, reason: String)
}

Constructors

  • PeerUp(peer: String, metadata: dict.Dict(String, String))

    A new peer has been discovered. Contains the peer ID and initial metadata.

  • PeerUpdate(peer: String, metadata: dict.Dict(String, String))

    A known peer’s metadata has been updated. Contains the peer ID and updated metadata.

  • PeerDown(peer: String, reason: String)

    A peer has left or become unavailable. Contains the peer ID and reason for departure.

Options for starting a discovery adapter.

pub type DiscoveryOptions {
  DiscoveryOptions(
    name: String,
    sync_interval_ms: Int,
    sync_timeout_ms: Int,
    telemetry_prefix: String,
    seed_peers: List(String),
    custom: dict.Dict(String, dynamic.Dynamic),
  )
}

Constructors

  • DiscoveryOptions(
      name: String,
      sync_interval_ms: Int,
      sync_timeout_ms: Int,
      telemetry_prefix: String,
      seed_peers: List(String),
      custom: dict.Dict(String, dynamic.Dynamic),
    )

    Arguments

    name

    Registered name for the adapter process

    sync_interval_ms

    How often to poll/sync with discovery backend (milliseconds)

    sync_timeout_ms

    Timeout for sync operations (milliseconds)

    telemetry_prefix

    Prefix for telemetry events

    seed_peers

    Initial list of seed peers (for bootstrap)

    custom

    Adapter-specific custom options

Callback type for discovery events.

pub type EventCallback =
  fn(DiscoveryEvent) -> Nil

Extended health information with sync status.

pub type HealthInfo {
  HealthInfo(
    status: HealthStatus,
    last_sync_time_ms: option.Option(Int),
    last_error: option.Option(String),
    known_peers_count: Int,
  )
}

Constructors

Health status of a discovery adapter.

Variants

  • Up: Adapter is fully operational
  • Degraded: Adapter is working but with issues (e.g., slow responses)
  • Down: Adapter is not operational
pub type HealthStatus {
  Up
  Degraded(reason: String)
  Down(reason: String)
}

Constructors

  • Up

    Adapter is fully operational

  • Degraded(reason: String)

    Adapter is operational but degraded

  • Down(reason: String)

    Adapter is down and cannot discover peers

Peer identifier used across the distribute library.

Matches the NodeId from registry/behaviour and handshake modules. Typically formatted as “node@host” (Erlang node naming convention).

pub type PeerId =
  String

Peer information including identity and metadata.

pub type PeerInfo {
  PeerInfo(id: String, metadata: dict.Dict(String, String))
}

Constructors

  • PeerInfo(id: String, metadata: dict.Dict(String, String))

Metadata associated with a discovered peer.

Contains information about the peer such as:

  • Service version
  • Capabilities
  • Health status
  • Custom attributes

All keys and values are strings for portability.

pub type PeerMetadata =
  dict.Dict(String, String)

Subscription identifier returned by subscribe().

Use this with unsubscribe() to stop receiving events.

pub opaque type SubscriptionId

Values

pub fn default_options(name: String) -> DiscoveryOptions

Create default discovery options.

pub fn is_permanent_error(error: DiscoveryError) -> Bool

Check if an error is permanent and should not be retried.

pub fn is_transient_error(error: DiscoveryError) -> Bool

Check if an error is transient and should be retried.

pub fn new_subscription_id(id: String) -> SubscriptionId

Create a new subscription ID.

pub fn subscription_id_value(id: SubscriptionId) -> String

Extract the string value from a subscription ID.

Search Document