Packages
cloister
0.15.0
0.18.1
0.18.0
0.17.3
0.17.2
0.17.1
0.17.0
0.16.0
0.15.0
0.14.0
0.13.0
0.12.5
0.12.4
0.12.3
0.12.2
0.12.1
0.12.0
0.11.0
0.10.3
0.10.2
0.10.1
0.10.0
0.9.0
0.8.0
0.7.5
0.7.4
0.7.3
0.7.2
0.7.1
0.7.0
0.6.5
0.6.4
0.6.3
retired
0.6.2
retired
0.6.1
retired
0.6.0
retired
0.5.0
0.4.4
0.4.3
0.4.2
0.4.1
0.4.0
0.3.9
0.3.8
0.3.7
0.3.6
0.3.5
0.3.4
0.3.3
0.3.2
0.3.1
0.3.0
0.2.2
0.2.1
0.2.0
0.1.4
0.1.3
0.1.2
0.1.1
0.1.0
The helper application to manage cluster, that uses hash ring to route requests to nodes. Automatically keeps track of connected nodes, provides helpers to determine where the term is to be executed, to multicast to all the nodes in the cluster and to retrieve current state of the cluster.
Current section
Files
Jump to
Current section
Files
lib/cloister/application.ex
defmodule Cloister.Application do
@moduledoc false
use Application
require Logger
@consensus 3
@consensus_timeout 2_000
@impl Application
def start(_type, _args) do
Logger.debug(
"[🕸️ :#{node()}] starting cloister with config:\n" <>
inspect(Application.get_all_env(:cloister))
)
children = [
Finitomata.child_spec(Cloister),
{Cloister.Manager, [state: Application.get_all_env(:cloister)]}
]
opts = [strategy: :one_for_all, name: Cloister.Supervisor]
Supervisor.start_link(children, opts)
end
@impl Application
def prep_stop(state),
do: Cloister.Monitor.terminate({:shutdown, :application}, state)
@impl Application
def start_phase(:warming_up, _start_type, phase_args) do
consensus = Keyword.get(phase_args, :consensus, consensus())
Application.put_env(:cloister, :consensus, consensus)
Logger.info(
"[🕸️ :#{node()}] Cloister → Phase I. Warming up, waiting for consensus [#{consensus}]."
)
wait_consensus(consensus, 0)
:ok
end
@impl Application
def start_phase(:rehash_on_up, _start_type, _phase_args) do
Logger.info("[🕸️ :#{node()}] Cloister → Phase II. Updating groups.")
# [AM] Cloister.Monitor.update_groups(phase_args)
:ok
end
@spec consensus :: non_neg_integer()
def consensus, do: Application.get_env(:cloister, :consensus, @consensus)
@spec ready? :: boolean()
defp ready? do
%{fsm: fsm} = Cloister.Monitor.state()
Finitomata.state(Cloister, fsm).current == :ready
end
@spec wait_consensus(consensus :: non_neg_integer(), retries :: non_neg_integer()) :: :ok
defp wait_consensus(consensus, retries) do
if retries > 0, do: Process.sleep(@consensus_timeout)
if ready?(), do: :ok, else: do_wait_consensus(consensus, retries)
end
@spec do_wait_consensus(
consensus :: non_neg_integer(),
retries :: non_neg_integer()
) :: :ok
defp do_wait_consensus(consensus, retries) do
nodes = Cloister.Monitor.siblings()
nodes
|> Enum.count()
|> case do
n when n < consensus ->
message = "[🕸️ :#{node()}] ⏳ retries: [#{retries}], nodes: [" <> inspect(nodes) <> "]"
case div(retries, 10) do
0 -> Logger.info(message)
r when r < 10 and rem(retries, 10) == 0 -> Logger.warn(message)
r when r >= 10 and rem(retries, 100) == 0 -> Logger.error(message)
_ -> :ok
end
wait_consensus(consensus, retries + 1)
_ ->
Logger.info("[🕸️ :#{node()}] ⌚ retries: [#{retries}], nodes: [" <> inspect(nodes) <> "]")
end
end
end