Visor
Visor adds VSR (View Stamped Replication) on top of GenServer.
If you want easy process supervision, add a Supervisor.
If you want easy replication, add Visor!
Usage
Create a module, use Visor, and implement the callbacks.
Let's create a replicated cache.
Define a module called Cache, set the initial_state to an empty map (%{}) and implement the
handle_commit callback which returns nil and merges the passed in data with the existing state.
defmodule Cache do
use Visor
@impl Visor
def initial_state(_opts), do: %{}
@impl Visor
def handle_commit({:add, item}, state) do
{:ok, nil, Map.merge(state, item)}
end
end
Now, add Cache to your application's supervision tree, and configure your cluster_size
(how many nodes you want this to replicate across)
def start(_type, _args) do
children = [
{Cache, cluster_size: 3}
]
opts = [strategy: :one_for_one, name: Cache.Supervisor]
Supervisor.start_link(children, opts)
endAnd that's it. You now have a cache that's replicated across 3 nodes. It handles replication, leader election, and recovery.
To add an item to your cache, commit the data:
Cache.commit({:add, %{user1: %{email: "advisor1@example.com"}}})
#=> nil
Cache.commit({:add, %{user2: %{email: "advisor2@example.com"}}})
#=> nilGet the full state of your cache with:
Cache.get()
#=> %{email: "advisor@example.com"}
%{
user1: %{email: "advisor1@example.com"},
user2: %{email: "advisor1@example.com"}
}
Pass in an accessor list to get_in your cache for quicker access:
Cache.get_in([:user1, :email])
#=> "advisor1@example.com"