A microlibrary that helps you spawn a process that lives at most once per cluster.
It can cope with netsplits by checking if the count of the currently connected nodes would have an absolute majority in the historically biggest known cluster size.
With an exemplary amount of 5 nodes in a healthy cluster, imagine the following split scenarios:
5
: No split - one of the nodes will host the singleton
4 - 1
: The cluster with 4 nodes will host the singleton
3 - 2
: The cluster with 3 nodes will host the singleton
1 - 2 - 2
: None of the clusters will host the singleton because none of
them have an absolute majority
1 - 2 - 1 - 1
: Even though the cluster with 2 nodes would have the majority,
it doesn't know that it's the cluster with the most nodes, so it doesn't
host the singleton
1 - 1 - 1 - 1 - 1
: None of these nodes will host the singleton either
As you can see, it is possible that in some net split situations, it is possible that no singleton is hosted. As such, this library is not for you if you often experience net splits and don't recover quickly from them.
In the start_link
callback of your GenServer, instead of directly using the GenServer
module to start the server, use Maracuja.start_link/3
:
The Maracuja
will call your module with start_server/2
when it has decided to start the module in this
cluster.
def MySingleton do
use GenServer
def start_link(args) do
Maracuja.start_link(__MODULE__, args, :my_global_name)
end
def start_server(args, name) do
GenServer.start_link(__MODULE__, args, name: name)
end
# init and rest of the server
end
Maracuja uses :global
to register the name, so you can find the pid of a singleton by passing its name to
:global.whereis_name
:
iex> :global.whereis_name(:my_global_name)
#Pid<0.170.0>
In the case the cluster is experiencing a net split and the current node is part of a faction that's too small, whereis_name
will return :undefined
!
- Support for other behaviours
- Maybe support for other coping strategies
The package can be installed by adding maracuja
to your list of dependencies in mix.exs
:
def deps do
[
{:maracuja, "~> 0.2.0"}
]
end
Documentation can be found at https://hexdocs.pm/maracuja.