macula_cluster (macula v0.20.3)

View Source

Cluster management utilities for Macula platform.

This module provides cluster infrastructure functions that other applications (like bc_gitops) can delegate to when running on the Macula platform.

Distribution

The ensure_distributed/0 function ensures the node is running in distributed mode. If not already distributed, it starts distribution with a generated node name.

Cookies are resolved in this priority order: 1. Application env: {macula, [{cookie, CookieValue}]} 2. Environment variable: MACULA_COOKIE or RELEASE_COOKIE 3. User's ~/.erlang.cookie file 4. Auto-generated (persisted to ~/.erlang.cookie)

Node Monitoring

The monitor_nodes/0 and unmonitor_nodes/0 functions wrap net_kernel:monitor_nodes/1 for subscribing to nodeup/nodedown messages.

bc_gitops Integration

When bc_gitops is running on the Macula platform, it detects these exports and delegates clustering operations here. This allows Macula to own cluster infrastructure while bc_gitops remains usable standalone.

Summary

Functions

Get the path to the cookie file.

Ensure this node is running in distributed mode.

Get the Erlang cookie for the cluster.

Get the short hostname of this machine.

Check if auto-clustering is currently active.

Check if this node is running in distributed mode.

Subscribe to node up/down events.

Get list of connected cluster nodes.

Read cookie from ~/.erlang.cookie file.

Resolve the cookie from various sources.

Set the Erlang cookie for this node and persist it.

Start automatic cluster formation with default options.

Start automatic cluster formation with options.

Stop automatic cluster formation.

Unsubscribe from node up/down events.

Functions

ensure_distributed()

-spec ensure_distributed() -> ok | {error, term()}.

Ensure this node is running in distributed mode.

If the node is already distributed, returns ok immediately. Otherwise, starts distribution with a generated node name in the format macula_host@hostname.

Examples:

  ok = macula_cluster:ensure_distributed().

get_cookie()

-spec get_cookie() -> atom().

Get the Erlang cookie for the cluster.

Resolves the cookie from various sources in priority order. If no cookie is found, generates and persists a new one.

Resolution Order: 1. Application env: {macula, [{cookie, CookieValue}]} 2. Environment variable: MACULA_COOKIE or RELEASE_COOKIE 3. User's ~/.erlang.cookie file 4. Auto-generated (persisted to ~/.erlang.cookie)

Examples:

  Cookie = macula_cluster:get_cookie().

get_hostname()

-spec get_hostname() -> string().

Get the short hostname of this machine.

Examples:

  "myhost" = macula_cluster:get_hostname().

is_clustered()

-spec is_clustered() -> boolean().

Check if auto-clustering is currently active.

Returns true if any cluster strategy is running (gossip, static, or DHT).

is_distributed()

-spec is_distributed() -> boolean().

Check if this node is running in distributed mode.

monitor_nodes()

-spec monitor_nodes() -> ok.

Subscribe to node up/down events.

After calling this function, the calling process will receive {nodeup, Node} and {nodedown, Node} messages when nodes join or leave the cluster.

Examples:

  ok = macula_cluster:monitor_nodes().
  receive
      {nodeup, Node} -> io:format("Node joined: ~p~n", [Node]);
      {nodedown, Node} -> io:format("Node left: ~p~n", [Node])
  end.

nodes()

-spec nodes() -> [atom()].

Get list of connected cluster nodes.

Returns all nodes connected to this node via Erlang distribution.

Examples:

  Nodes = macula_cluster:nodes().
  %% => ['node1@host1', 'node2@host2']

resolve_cookie()

-spec resolve_cookie() -> {ok, atom()} | {error, not_found}.

Resolve the cookie from various sources.

set_cookie(Cookie)

-spec set_cookie(atom() | binary()) -> ok.

Set the Erlang cookie for this node and persist it.

Sets the cookie for the current node and attempts to persist it to ~/.erlang.cookie for future sessions.

Examples:

  ok = macula_cluster:set_cookie(my_secret_cookie).
  ok = macula_cluster:set_cookie(<<"my_secret_cookie">>).

start_cluster()

-spec start_cluster() -> ok | {error, term()}.

Start automatic cluster formation with default options.

Uses the static strategy by default, reading nodes from: 1. Application env: {macula, [{cluster_nodes, [Node1, Node2, ...]}]} 2. Environment variable: CLUSTER_NODES (comma-separated)

If no nodes are configured, starts the DHT-based discovery strategy.

Examples:

  %% With CLUSTER_NODES env var set
  ok = macula_cluster:start_cluster().
 
  %% Or configure in sys.config
  {macula, [{cluster_nodes, ['node1@host1', 'node2@host2']}]}

start_cluster(Opts)

-spec start_cluster(map()) -> ok | {error, term()}.

Start automatic cluster formation with options.

Options: - strategy: gossip (default), static, mdns, dht, or auto - nodes: List of node atoms (for static strategy) - reconnect_interval: Milliseconds between reconnect attempts (default 5000) - callback: PID or {Module, Function} to receive cluster events

Gossip options (for gossip strategy): - multicast_addr: IPv4 multicast address (default {230, 1, 1, 251}) - port: UDP port (default 45892) - broadcast_interval: Milliseconds between broadcasts (default 1500) - multicast_ttl: TTL for multicast packets (default 1 = same subnet) - secret: Optional binary secret for HMAC authentication

Strategy selection: - gossip: UDP multicast gossip for zero-config LAN (like libcluster Gossip) - static: Uses a known list of nodes (like libcluster Epmd strategy) - mdns: Uses mDNS for local network discovery - dht: Uses Macula's DHT for internet-scale discovery - auto: Chooses strategy based on configuration

Examples:

  %% Gossip strategy for zero-config LAN discovery (recommended)
  ok = macula_cluster:start_cluster(#{
      strategy => gossip
  }).
 
  %% Gossip with custom multicast group
  ok = macula_cluster:start_cluster(#{
      strategy => gossip,
      multicast_addr => {239, 1, 1, 1},
      port => 9999,
      secret => <<"my-cluster-secret">>
  }).
 
  %% Static strategy with explicit nodes
  ok = macula_cluster:start_cluster(#{
      strategy => static,
      nodes => ['node1@host1', 'node2@host2']
  }).
 
  %% mDNS strategy for local network
  ok = macula_cluster:start_cluster(#{
      strategy => mdns
  }).
 
  %% DHT strategy for internet-scale
  ok = macula_cluster:start_cluster(#{
      strategy => dht
  }).

stop_cluster()

-spec stop_cluster() -> ok.

Stop automatic cluster formation.

Stops the cluster strategy process and disconnects from managed nodes.

unmonitor_nodes()

-spec unmonitor_nodes() -> ok.

Unsubscribe from node up/down events.

Stops the calling process from receiving nodeup/nodedown messages.