Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

alii/reki

Open more actions menu

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

73 Commits
73 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

reki

A Gleam actor registry that manages actors by key, similar to Discord's gen_registry in Elixir. It provides a way to look up or start actors on demand ensuring only one actor exists per key, while automatically cleaning up dead processes.

Installation

gleam add reki

Usage

import gleam/erlang/process
import gleam/list
import gleam/option
import gleam/otp/actor
import gleam/otp/static_supervisor as supervisor
import reki

pub type ChannelMsg {
  Subscribe(process.Subject(String))
  Publish(String)
}

pub type ChannelState {
  ChannelState(name: String, subscribers: List(process.Subject(String)))
}

fn start_channel(name: String) {
  actor.new(ChannelState(name:, subscribers: []))
  |> actor.on_message(fn(state, msg) {
    println("Channel" <> state.name <> " received message: " <> inspect(msg))

    case msg {
      Subscribe(sub) ->
        actor.continue(ChannelState(..state, subscribers: [sub, ..state.subscribers]))
      Publish(text) -> {
        list.each(state.subscribers, process.send(_, text))
        actor.continue(state)
      }
    }
  })
  |> actor.start
}

pub fn main() {
  let channels = reki.new()

  let assert Ok(_) =
    supervisor.new(supervisor.OneForOne)
    |> supervisor.add(reki.supervised(channels))
    |> supervisor.start

  let assert Ok(general) =
    reki.lookup_or_start(channels, "general", start_channel)

  let inbox = process.new_subject()
  process.send(general, Subscribe(inbox))

  process.send(general, Publish("Hello!"))

  let assert Ok(same_channel) =
    reki.lookup_or_start(channels, "general", start_channel)

  process.send(same_channel, Publish("Also hello!"))

  // You can also lookup without starting
  case reki.lookup(channels, "general") {
    option.Some(channel) -> process.send(channel, Publish("Found it!"))
    option.None -> {
      // channel not found ...
      todo
    }
  }
}

How it works

Like gen_registry, reki is an Erlang gen_server that stores {key, subject} mappings in ETS for fast O(1) lookups. The gen_server serializes "lookup or start" operations to prevent races when multiple processes request the same key simultaneously.

  • Fast reads: Existing actors are looked up directly from ETS, bypassing the gen_server
  • Automatic cleanup: The registry links to child processes and traps exits, removing entries from ETS when they die
  • Concurrent safety: Start operations are serialized through the gen_server

About

Registry library for Gleam, much like gen_registry

Topics

Resources

Stars

Watchers

Forks

Releases

Contributors

Languages

Morty Proxy This is a proxified and sanitized view of the page, visit original site.