mule/runtime/peer_global

The distributed-Erlang lock peer — a port of Oban.Peers.Global. Leadership is a :global lock on the instance name: set_lock with zero retries either takes it or reports the holder elsewhere, re-checked every interval (a :global lock releases when its holding process dies, so a crashed leader frees the cluster without any TTL). Requires a functional Distributed Erlang cluster — pair it with the PG notifier; on a single unclustered node it is simply always leader, like always_leader with extra steps.

Structure mirrors runtime/peer_database: the actor writes its leadership into the peer cell on every tick (the gates’ pure read), the first election runs synchronously in the initialiser, and a supervisor shutdown hands off by dropping the lock and notifying the Leader channel. Unlike the database peer there is no lease to renew, so the leader checks at the same cadence as followers (Peers.Global has no leader boost), and elections cannot error (no exception telemetry arm). Followers learn get_leader from the winner’s Lock broadcast (Peers.Global’s %{lock: conf.node}) instead of a database read — before the first broadcast arrives it is unknown.

Types

pub type Message {
  Elect
  IsLeader(reply: process.Subject(Bool))
  GetLeader(reply: process.Subject(option.Option(String)))
  LeaderHeard(notifier.Notification)
  Shutdown
}

Constructors

pub type State {
  State(
    name: String,
    node: String,
    notifier: notifier.Notifier,
    interval: duration.Duration,
    is_leader: Bool,
    leader: option.Option(String),
    self_subject: process.Subject(Message),
  )
}

Constructors

Values

pub fn child(
  name name: String,
  node node: String,
  notifier notifier: notifier.Notifier,
  interval interval: duration.Duration,
  peer_name peer_name: process.Name(Message),
) -> supervision.ChildSpecification(Nil)

Supervise the peer actor as a single worker, registered under peer_name so reader can reach it for get_leader.

pub fn reader(
  name name: String,
  peer_name peer_name: process.Name(Message),
) -> peer.Peer

Build the Peer read surface: leadership is the pure cell read (the gate hot path), and get_leader calls into the named peer actor for the last broadcast leader (never a database). None when the peer is down or no Lock has been heard yet.

pub fn start(
  name name: String,
  node node: String,
  notifier notifier: notifier.Notifier,
  interval interval: duration.Duration,
) -> Result(
  actor.Started(process.Subject(Message)),
  actor.StartError,
)

Start the peer actor directly (the child spec wraps this). Public so a test can hold the actor’s Subject and address its process.

Search Document