eliasdarruda

eliasdarruda

Ra_registry — A Distributed Registry based on Raft using rabbitmq/ra

Introduction

Introducing RaRegistry: A Distributed, Raft-Backed Process Registry for Elixir

If you’re building distributed Elixir applications and need a reliable, consistent process registry, RaRegistry is a new library worth exploring. It offers a drop-in alternative to Elixir’s built-in Registry, but with distributed consensus powered by Ra, RabbitMQ’s implementation of the Raft protocol.​

Features:

  • Support for both :unique and :duplicate registration modes
  • Automatic process monitoring and cleanup
  • Built on Ra, RabbitMQ’s implementation of the Raft consensus protocol
  • Regular operations with strong consistency during normal cluster operation
  • Familiar API similar to Elixir’s built-in Registry
  • Enhanced recovery mechanisms for handling abrupt node down scenarios like SIGKILL
  • Seamless integration with GenServer via the :via tuple registration

Usage

Dependency

def deps do
  [
    {:ra_registry, "~> 0.1.2"}
  ]
end

Example implementation

defmodule MyApp do
  # Add RaRegistry to your application supervision tree
  def start(_type, _args) do
    children = [
      # Start RaRegistry after any kind of node discovery mechanism such as libcluster
      # You can configure any configuration related with the :ra cluster under ra_config.
      # wait for nodes range ms is a random range between two milliseconds values to ensure nodes are properly connected
      {
        RaRegistry,
        keys: :unique, # or :duplicate
        name: MyApp.Registry,
        ra_config: %{data_dir: ~c"/tmp/ra"},
        wait_for_nodes_range_ms: 3000..5000
      },
      
      # Other children in your supervision tree...
    ]

    opts = [strategy: :one_for_one, name: MyApp.Supervisor]
    Supervisor.start_link(children, opts)
  end
end

defmodule MyApp.Server do
  use GenServer
  
  def start_link(opts) do
    GenServer.start_link(__MODULE__, [], name: {:via, RaRegistry, {MyApp.Registry, opts[:id]}})
  end
  
  def call(id, message) do
    GenServer.call(via_tuple(id), message)
  end

  defp via_tuple(id), do: {:via, RaRegistry, {MyApp.Registry, id}}
  
  # GenServer implementation
  def init(state), do: {:ok, state}
  def handle_call(:ping, _from, state), do: {:reply, :pong, state}
  def handle_call({:get, key}, _from, state), do: {:reply, Map.get(state, key), state}
  def handle_call({:set, key, value}, _from, state), do: {:reply, :ok, Map.put(state, key, value)}
end

# Then, in your application code:
{:ok, pid} = MyApp.Server.start_link(id: "user_123")

# This call will work from any node in the cluster
MyApp.Server.call("user_123", {:set, :name, "John"})
MyApp.Server.call("user_123", {:get, :name}) # => "John"

# Should return already started regardless of the node you try to start the Server
{:error, {:already_started, ^pid}} = MyApp.Server.start_link(id: "user_123")

Consistency and Recovery

Consistency Model

RaRegistry offers these consistency guarantees:

  • Normal Operation: Operations use the Raft consensus protocol via Ra, providing strong consistency when a majority of nodes are available
  • State Machine Atomicity: Operations within the Ra state machine are atomic and either fully succeed or have no effect
  • Best-Effort Recovery: During failure scenarios like SIGKILL of the leader, our implementation employs aggressive recovery mechanisms that prioritize cluster recovery

It’s important to understand that:

  • The custom recovery mechanisms we’ve implemented extend beyond the standard Raft protocol
  • After recovery, the system returns to a consistent state, though some in-flight operations might result in errors due to incomplete execution

Recovery Capabilities

RaRegistry includes specialized recovery mechanisms to handle various failure scenarios:

  • Automatic leader election after clean node failures
  • Emergency recovery procedures for SIGKILL scenarios
  • Self-healing mechanisms when nodes rejoin the cluster
  • Cleanup of dead process registrations

Most Liked

dimitarvp

dimitarvp

Seeing this phrase makes me twitch at this point. LLMs love it though. :003:

Library looks good, IMO it was time for a new player in the area. I too took a quick look in the code. Good impressions so far.

hauleth

hauleth

I was thinking more about something like Imhotep, CleopatRa, or stuff like BadRomance.

eliasdarruda

eliasdarruda

You’re absolutely right — that was definitely an oversight in the docs :sweat_smile:

I’ve updated the description to clarify that this doesn’t prioritize availability. That was definitely an inaccurate implication before.

Where Next?

Popular in Announcing Top

danschultzer
None of the current solutions worked well for me, so I went ahead and built a user management system from scratch. This project took far...
548 29603 241
New
josevalim
Hi everyone, We would like to announce that Plataformatec is working on a new MySQL driver called MyXQL. Our goal is to eventually integ...
New
dominicletz
Hi, I thought I had posted my library before but seems I hadn’t. The project is still in early stages but it’s growing and so I think it...
New
KronicDeth
Elixir plugin for JetBrain’s IntelliJ Platform (including Rubymine) This is a plugin that adds support for Elixir to JetBrains IntelliJ...
289 36352 110
New
versilov
Could not wait for the missing Elixir ML libraries to appear, so, I wrote one myself, taking https://github.com/sdwolfz/exlearn as a foun...
New
hpopp
After just over two years in development, this latest version of Pigeon is what I finally consider done in regards to my original vision ...
New
zoltanszogyenyi
Hey everyone :waving_hand: Excited to join this forum - I am one of the founders and current project maintainers of a popular and open-s...
New
mplatts
With HEEX released we decided to start a components library using Tailwind CSS - check it out here: Petal Components. We also have a boi...
New
wfgilman
I’ve cleaned up and open sourced three financial libraries I was using for my company. They are bindings for the APIs of these three comp...
New
mattludwigs
Grizzly is a library for working with Z-Wave devices. Z-Wave is a low-frequency radio protocol for controlling smart home devices on a me...
New

Other popular topics Top

WestKeys
Currently suffering from paralysis by [HTTP client] analysis. This is rather unusual in Elixirland as there tends to be consensus on the ...
New
Darmani72
If I have a post route which an argument: post /my_post_route/:my_param1, MyController.my_post_handler How would get the post params ...
New
baxterw3b
Hi guys, i’m new in the Elixir world, and i have to say, that i love it! i’m having some problem to understand anonymous functions with ...
New
pmjoe
I have a relationship of love and hate with Elixir. Lots of things are just absolutely right, but there are some things that are kind of ...
New
nobody
Hi! In PHP: $_SERVER[‘SERVER_ADDR’] - in Elixir? Searched the docs for ip address and the web, no good results. Thanks!
New
KronicDeth
Elixir plugin for JetBrain’s IntelliJ Platform (including Rubymine) This is a plugin that adds support for Elixir to JetBrains IntelliJ...
289 36352 110
New
Brian
What is the proper way to load a module from a file in to IEX? In the python world, doing something like this pretty standard: from ....
New
AstonJ
We’ve put together this wiki for Phoenix LiveView - please feel free to add any info you feel is worth including. What is Phoenix LiveV...
New
JakeBecker
TL;DR: I’ve just released an implementation of Microsoft’s IDE-independent Language Server Protocol for Elixir. It adds language support ...
1144 54120 245
New
sergio
Kind of like when jquery came out, it was super necessary. Existing drag and drop libraries have a bunch of baggage to support old browse...
New

Latest on Elixir Forum

Elixir Forum

We're in Beta

About us Mission Statement