classy ¶Main interface module of Classy application.
Note: business releases can install hooks by setting
classy:setup_hooks application environment variable to a tuple
{Module, Function, Args}.
This MFA can contain calls to various classy:on_... functions.
-type run_level() :: stopped |
single |
cluster |
quorum.
See Run level
-type kick_intent() :: term().
Kick intent is an arbitrary term passed to classy:pre_kick/2 and classy:post_kick/2 hooks.
pre_kick may match on intent to prevent node from leaving the cluster in certain cases,
while to post_kick this value is merely informational.
Classy itself uses the following intents:
join:
Site is leaving the cluster to immediately join a different one.
kicked:
Site detects that it got kicked from the cluster by a third party.
autoclean:
Site is kicked by the autoclean logic.
-type join_intent() :: term().
Join intent is an arbitrary term passed to classy:pre_join/2 and classy:post_join/2 hooks.
pre_join may match on intent to prevent join in certain cases,
while to post_join this value is merely informational.
Classy itself uses the following intents:
autocluster:
When join is triggered by autocluster.
-type membership_change_hook() :: fun((cluster_id(),
_Local :: site(), _Remote :: site(),
_IsMember :: boolean()) -> _).
-type cluster_info() :: #{infos := #{node() => info()},
bad_nodes := #{node() => _}}.
-type info() :: #{cluster := cluster_id() | undefined,
site := site() | undefined,
last_update := classy_lib:unix_time_s() | undefined,
peers := #{site() => peer_info()}, atom() => _}.
-type peer_info() :: #{node := node() | undefined,
connected := boolean(),
last_update := classy_lib:unix_time_s()}.
-type site() :: binary().
Unique random persistent identifier of the site. See Site ID.
-type cluster_id() :: binary().
Unique random persistent identifier of the cluster. See Cluster ID.
-spec enrich_site_info(fun((info()) -> info()),
classy_hook:prio()) -> classy_hook:hook().
Register a hook that can add entries to the map returned by classy:info/0.
-spec run_level(fun((run_level(), run_level()) -> _),
classy_hook:prio()) -> classy_hook:hook().
Register a hook that is executed on change of the run level of the local site.
-spec pre_autocluster(fun((cluster_info(),
Discovered) -> Discovered),
classy_hook:prio()) -> classy_hook:hook() when Discovered ::
[{cluster_id(),
[node()]}].
Register a hook that filters and ranks nodes for autocluster. It allows the business code to pick the most appropriate cluster for automatic join.
WARNING: this hook cannot have side effects.
-spec pre_autoclean(fun((Remote) -> ok | {error, _}),
classy_hook:prio()) -> classy_hook:hook() when Remote ::
site().
Register a hook that runs before autoclean finalizes the decision to kick a down site.
WARNING: this hook cannot have side effects.
-spec post_kick(fun((OldCluster, Local,
kick_intent()) -> _),
classy_hook:prio()) -> classy_hook:hook() when OldCluster ::
cluster_id(),
Local :: site().
Register a hook that is executed after the local site leaves a cluster. This hook can perform destructive actions associated with cleanup.
-spec pre_kick(fun((cluster_id(), Remote,
kick_intent()) -> ok | {error, _}),
classy_hook:prio()) -> classy_hook:hook() when Remote ::
site().
Register a hook that verifies whether or not a site can be kicked from the cluster. This hook runs on the node that initiates the kick.
WARNING: this hook cannot have side effects.
-spec post_join(fun((cluster_id(), Local,
JoinedTo) -> _),
classy_hook:prio()) -> classy_hook:hook() when Local ::
site(),
JoinedTo ::
node().
Register a hook that is executed after the local site joins a cluster.
It is guaranteed to be called at least once, and must be idempotent.
-spec pre_join(fun((cluster_id(), Remote, node(),
join_intent()) -> ok | {error, _}),
classy_hook:prio()) -> classy_hook:hook() when Remote ::
site().
Register a hook that is executed before the local node joins a different cluster.
WARNING: this hook should not have side effects. It should only check if it is ok to join.
-spec on_membership_change(membership_change_hook(),
classy_hook:prio()) -> classy_hook:hook().
Register a hook that is executed when a site joins or leaves a cluster.
-spec on_peer_connection_change(Fun,
classy_hook:prio()) -> classy_hook:hook() when Fun ::
fun((cluster_id(),
Local,
Remote,
node(),
_IsConnected ::
boolean()) -> _),
Local ::
site(),
Remote ::
site().
Register a hook that is executed when a site changes
status from connected (true) to disconnected (false) and vice versa.
Note: this hook runs in the classy main process. Hence it should avoid blocking it.
WARNING: status change to false is not indicative of the remote site being actually down.
This can happen during a network partition.
-spec on_create_site(fun((site()) -> _),
classy_hook:prio()) -> classy_hook:hook().
This callback is called once per site.
-spec on_create_cluster(fun((cluster_id(), Local) -> _),
classy_hook:prio()) -> classy_hook:hook() when Local ::
site().
This callback is executed once per cluster by the site that originally creates the cluster.
-spec on_node_init(fun(() -> _),
classy_hook:prio()) -> classy_hook:hook().
Register a hook that is executed when the node (not the site) starts.
It is called before classy_node:the_site/0 and classy_node:the_cluster/0
are initialized,
and can be used to override the default cluster and site initialization logic.
Calculate how many nodes can be down while cluster still can maintain quorum.
-spec quorum(config |
running |
non_neg_integer()) -> pos_integer().
Calculate the number of nodes required for the quorum:
Integer:
any integer value
config:
Return value of ‘classy.quorum’ application environment variable
running:
Quorum among the running sites, not less than quorum(config)
-spec at_lower_level(classy_node:run_level_atom(),
fun(() -> Ret)) -> {ok, Ret} |
{error | exit | throw,
_Reason,
_Stacktrace}.
Lower the run level to the given value and run the specified function.
This function can be used to implement migrations that require business applications to be stopped.
-spec nodes(all | connected | disconnected) -> [node()].
List all peer nodes.
Important to note: this function returns node names of peer sites. Random connected nodes, such as shells or classy sites that are not member of the current cluster, are excluded.
-spec sites() -> [site()].
List IDs of peer sites.
-spec kick_node(node(), kick_intent()) -> ok |
{error, _}.
Translate node name to a site ID and kick it via classy:kick_site/2.
-spec kick_site(site(), kick_intent()) -> ok |
{error, _}.
Remove a site from the cluster. Target site can be local or remote: it is allowed for a site to kick itself from the cluster.
The kicked site creates an entirely new cluster_id(), and joins it as a singleton member.
Local site (one that initiates kick) runs the following hooks
with Intent equal to the value of the argument:
If the target site is not the same as the local site,
then it also runs classy:post_kick/2 with pre-defined intent kicked.
-spec join_node(node(), join_intent()) -> ok |
{error, _}.
Join the local site to the cluster of a remote node.
This function allows a node to join a cluster by connecting to a known peer.
Arguments:
Note: while the majority of classy APIs work with site IDs, joining a cluster is always done via regular Erlang node name.
-spec node_of_site(site(), boolean()) -> {ok, node()} |
undefined.
Locate a node that is currently hosting a site.
If OnlyConnected flag is set,
undefined is returned when the site is locally unreachable
(even if its node is otherwise known).
-spec info([node()]) -> cluster_info().
Gather classy:info/0 from a set of nodes.
The nodes don’t have to be in the same cluster.
WARNING: as a side effect of calling this function,
the current node will establish Erlang distribution connection to all nodes in the list.
While this won’t affect code using classy:nodes(connected) API,
it may confuse code using plain erlang:nodes().
-spec info() -> info().
Provide general information about the local node.