distribute/discovery

High-level discovery API for the distribute library.

This module provides a unified facade for the discovery layer, managing the default BEAM discovery adapter as a singleton. Other modules can use these functions without explicitly passing adapter handles.

Architecture

The discovery layer is designed as a pluggable system:

Usage

Start the discovery as part of your supervision tree:

import distribute/discovery
import gleam/otp/static_supervisor as supervisor

pub fn start_app() {
  supervisor.new(supervisor.OneForOne)
  |> supervisor.add(discovery.child_spec())
  |> supervisor.start()
}

Then use the discovery functions:

// Subscribe to peer events
let callback = fn(event) {
  case event {
    discovery.PeerUp(peer, _meta) -> io.println("Peer joined: " <> peer)
    discovery.PeerDown(peer, _reason) -> io.println("Peer left: " <> peer)
    _ -> Nil
  }
}
let assert Ok(sub_id) = discovery.subscribe(callback)

// Get current peers
let assert Ok(peers) = discovery.snapshot()

// Check health
case discovery.health() {
  discovery.Up -> io.println("Discovery is healthy")
  discovery.Degraded(reason) -> io.println("Degraded: " <> reason)
  discovery.Down(reason) -> io.println("Down: " <> reason)
}

Values

pub fn child_spec() -> supervision.ChildSpecification(
  types.AdapterHandle,
)

Create a child specification for starting the discovery adapter under a supervisor.

This is the recommended way to start the discovery layer. The adapter will be automatically restarted if it crashes.

Example

import distribute/discovery
import gleam/otp/static_supervisor as supervisor

supervisor.new(supervisor.OneForOne)
|> supervisor.add(discovery.child_spec())
|> supervisor.start()
pub const default_adapter_name: String

The registered name for the default discovery adapter process.

This name is used to look up the singleton adapter instance. You typically don’t need to use this directly - the functions in this module handle the lookup automatically.

pub fn health() -> types.HealthStatus

Get the health status of the discovery adapter.

Returns:

  • Up - Discovery is fully operational
  • Degraded(reason) - Discovery is working but with issues
  • Down(reason) - Discovery is not operational

Example

case discovery.health() {
  types.Up -> io.println("All good!")
  types.Degraded(r) -> io.println("Warning: " <> r)
  types.Down(r) -> io.println("Error: " <> r)
}
pub fn lookup(
  peer_id: String,
) -> Result(types.PeerInfo, types.DiscoveryError)

Lookup a specific peer by ID.

Returns the peer’s info if known, or PeerNotFound error otherwise.

Example

case discovery.lookup("node2@host") {
  Ok(peer) -> io.println("Found peer with metadata")
  Error(types.PeerNotFound(_)) -> io.println("Peer not found")
  Error(_) -> io.println("Discovery error")
}
pub fn snapshot() -> Result(
  List(types.PeerInfo),
  types.DiscoveryError,
)

Get a snapshot of all currently known peers.

Returns a list of peers with their metadata at the current point in time. This is a consistent snapshot - peers won’t change during iteration.

Example

let assert Ok(peers) = discovery.snapshot()
list.each(peers, fn(peer) {
  io.println("Peer: " <> peer.id)
})
pub fn start_link() -> Result(
  types.AdapterHandle,
  types.DiscoveryError,
)

Start the discovery adapter directly without supervision.

Note: For production use, prefer child_spec() with a supervisor. This function is primarily useful for testing or simple scripts.

Returns the adapter handle on success, or an error if startup fails.

pub fn subscribe(
  callback: fn(types.DiscoveryEvent) -> Nil,
) -> Result(types.SubscriptionId, types.DiscoveryError)

Subscribe to peer membership events.

The callback will be invoked for each peer event (up, down, update). Returns a subscription ID that can be used to unsubscribe later.

Example

let callback = fn(event) {
  case event {
    types.PeerUp(peer, meta) -> 
      io.println("New peer: " <> peer)
    types.PeerDown(peer, reason) -> 
      io.println("Peer left: " <> peer)
    types.PeerUpdate(peer, meta) -> 
      io.println("Peer updated: " <> peer)
  }
}
let assert Ok(sub_id) = discovery.subscribe(callback)
pub fn unsubscribe(
  id: types.SubscriptionId,
) -> Result(Nil, types.DiscoveryError)

Unsubscribe from peer events.

After calling this function, the callback associated with the given subscription ID will no longer receive events.

Search Document