reki

Types

A registry that manages actors by key. Similar to Discord’s gen_registry, this allows you to look up or start actors on demand, ensuring only one actor exists per key.

Architecture

Reki uses an ETS table for fast O(1) lookups, with an Erlang gen_server that handles process lifecycle (starting new actors, cleaning up dead ones). When a managed actor dies, the gen_server receives an EXIT signal and removes the stale entry from ETS.

The gen_server implements the OTP supervisor protocol (which_children, count_children), registers as type: supervisor in its child spec, and properly terminates all children on shutdown.

The ETS table is owned by the gen_server. If it crashes, the BEAM automatically destroys the table. When the supervisor restarts it, a fresh table is created.

Stale entries

There’s a brief window between when a process dies and when reki processes the EXIT signal. During this window, lookup or lookup_or_start may return a stale Subject pointing to a dead process. This is the tradeoff for fast O(1) lookups.

pub opaque type Registry(key, msg)

The gen_server’s registered name

pub type ServerName =
  atom.Atom

The ETS table name

pub type TableName =
  atom.Atom

Values

pub fn lookup(
  registry: Registry(key, msg),
  key: key,
) -> option.Option(process.Subject(msg))

Looks up an actor by key in the registry, without starting one if missing.

Returns None if no actor exists for the given key. This is a direct ETS read, so it’s fast but may return a stale Subject if a process just died.

Use lookup_or_start if you want to start an actor when the key is missing.

pub fn lookup_or_start(
  registry: Registry(key, msg),
  key: key,
  start_fn: fn(key) -> Result(
    actor.Started(process.Subject(msg)),
    actor.StartError,
  ),
) -> Result(process.Subject(msg), actor.StartError)

Looks up an actor by key, or starts one if it doesn’t exist.

This is the primary function for getting an actor from the registry. It first checks ETS for an existing entry (fast O(1) lookup), and only goes through the registry gen_server if the key isn’t found.

In rare cases, this may return a stale Subject if a process just died but reki hasn’t processed the EXIT yet.

pub fn new() -> Registry(key, msg)

Create a registry. Call this at the start of your program before creating the supervision tree.

Important: Each call creates unique atoms for the server name and ETS table name. Atoms are never garbage collected by the BEAM, so this function must only be called a fixed number of times (e.g. once per registry at app startup). Do not call new() dynamically in a loop or on each request.

pub fn start(
  registry: Registry(key, msg),
) -> Result(actor.Started(Registry(key, msg)), actor.StartError)

Start the registry. You likely want to use the supervised function instead, to add the registry to your supervision tree, but this may be useful in tests.

pub fn supervised(
  registry: Registry(key, msg),
) -> supervision.ChildSpecification(Registry(key, msg))

A specification for starting the registry under a supervisor.

The registry declares itself as a supervisor in the child spec, since it manages child processes and implements the OTP supervisor protocol.

Search Document