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
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.