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.

nulltree

nulltree

Fair; then again, the name is quite… clear. I do value that.

@eliasdarruda, thank you for this contribution to the ecosystem! <3

garrison

garrison

Great work, it’s wonderful to see more consistent distributed libraries/systems being built in Elixir!

I think it’s very important to document exactly what this means. Unlike availability, it is actually possible to guarantee consistency 100% of the time, so that is often the more useful guarantee to make. If you are not making those guarantees it’s important that users know exactly when they will be making inconsistent reads/writes.

Of course this is a brand new project so I’m sure docs are still WIP. I did a quick scan through the code and it looks very nice, so again - great work :slight_smile:

Where Next?

Popular in Libraries Top

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
mathieuprog
Hello :wave: Allow me to introduce you to Tz, an alternative time zone database support to Tzdata. Why another library? First and fore...
New
Crowdhailer
The latest release of Ace (0.10.0) includes serving content over HTTP/2. I have started writing a webserver to teach my self more about...
New
seancribbs
Today I released a new dialyzer Mix task as the dialyzex package! At the time we started writing this task, the existing dialyzer integra...
New
sasajuric
I’d like to announce a small library called boundaries. This is an experimental project which explores the idea of enforcing boundaries ...
New
woylie
I released Doggo, a collection of unstyled Phoenix components. Features Unstyled Phoenix components. Storybook that can be added to...
New
mindok
What is ContEx? A pure Elixir server-side data plotting/charting library outputting SVG. It has nice barcharts in particular and works g...
New
Azolo
Hey everyone, I just released WebSockex which is a Elixir WebSocket client. WebSockex strives to work as a OTP special process, be RFC6...
New
Hal9000
Here is my first stab at this. README pasted below. https://github.com/Hal9000/elixir_random Comments and critiques are welcome. Th...
New
maltoe
Hello! Came here to announce ChromicPDF, a pet project PDF generator I’ve been working on for the past few months. Why another PDF gener...
New

Other popular topics Top

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
jerry
Good day to you all. I have been struggling to get a query involving like and ilike to work. Can anyone assist me on this, please? pro...
New
Jim
As a follow up to my earlier question: I have the code compiling and running but not getting a successful login from the rest server. ...
New
lk-geimfari
What is most correct way to open, read and parse JSON file with poison? For example if we have example.json file in root of some projec...
New
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 27727 240
New
rms.mrcs
Hi, I need to transform a list of numbers into a map where the keys are the indexes and the values are the original values of the list....
New
shahryarjb
Hello, I have map which I want to convert it to string like this: the map: %{last_name: "tavakkoli", name: "shahryar"} the string I ne...
New
fireproofsocks
Forgive me if this is obvious, but how does one delete a database record WITHOUT selecting it first? https://hexdocs.pm/ecto/Ecto.Repo.h...
New
AstonJ
by Lance Halvorsen Elixir and Phoenix are generating tremendous excitement as an unbeatable platform for building modern web application...
460 27162 124
New
aesmail
Hello guys, I have finally made it. I created an admin interface for a framework. It’s been on my todo list for years and with the curre...
New

Sub Categories:

We're in Beta

About us Mission Statement