NoNoncense.MachineId.ConflictGuard (NoNoncense v2.0.0)

Copy Markdown View Source

Guards against machine ID conflicts between nodes by broadcasting each node's machine ID to newly connected peers and calling on_conflict whenever a duplicate is detected.

When to use

ConflictGuard is useful when running NoNoncense with strategies that do not provide server-side uniqueness guarantees, such as NoNoncense.MachineId.Strategy.HostIdentifiers or NoNoncense.MachineId.Strategy.EnvironmentVariable. It adds a runtime cross-check that a split-brain or misconfiguration hasn't caused two nodes to end up with the same ID.

For lease-based strategies (SqlLease, RedisLease), the external coordinator already prevents duplicate IDs, so ConflictGuard provides little additional value — though it won't hurt to enable it.

Requires distributed Erlang

ConflictGuard only works when nodes are connected to each other via distributed Erlang (i.e. started with --name / --sname and a shared cookie). Without it, the conflict checks never run.

Default action

When a conflict is detected, the newer node calls on_conflict, which defaults to halting the node immediately via :erlang.halt(111).

Usage

NoNoncense.MachineId starts ConflictGuard by default. Pass enable_conflict_guard?: false to disable it. When enabled through NoNoncense.MachineId, the supervisor derives the guard's name and resolves the machine ID through its lease manager. A conflict signals the lease manager that its lease was lost:

{NoNoncense.MachineId,
 strategy: NoNoncense.MachineId.Strategy.HostIdentifiers,
 instances: [[base_key: System.fetch_env!("BASE_KEY")]]}

When started manually, supply :machine_id to resolve the ID, and :on_conflict to override the default halt behaviour.

Summary

Functions

Returns a specification to start this module under a supervisor.

Starts the conflict guard.

Types

opt()

@type opt() ::
  {:name, GenServer.name()}
  | {:on_conflict, (-> any())}
  | {:machine_id, integer() | (-> integer())}

Functions

child_spec(init_arg)

Returns a specification to start this module under a supervisor.

See Supervisor.

start_link(opts \\ [])

@spec start_link([opt()]) :: GenServer.on_start()

Starts the conflict guard.