4.1 Module 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.

4.1.1 Types

run_level()
-type run_level() :: stopped |
                     single |
                     cluster |
                     quorum.

See Run level

kick_intent()
-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.
join_intent()
-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.
membership_change_hook()
-type membership_change_hook() :: fun((cluster_id(),
                                       _Local :: site(), _Remote :: site(),
                                       _IsMember :: boolean()) -> _).
cluster_info()
-type cluster_info() :: #{infos := #{node() => info()},
                          bad_nodes := #{node() => _}}.
info()
-type info() :: #{cluster := cluster_id() | undefined,
                  site := site() | undefined,
                  last_update := classy_lib:unix_time_s() | undefined,
                  peers := #{site() => peer_info()}, atom() => _}.
peer_info()
-type peer_info() :: #{node := node() | undefined,
                       connected := boolean(),
                       last_update := classy_lib:unix_time_s()}.
site()
-type site() :: binary().

Unique random persistent identifier of the site. See Site ID.

cluster_id()
-type cluster_id() :: binary().

Unique random persistent identifier of the cluster. See Cluster ID.

4.1.2 Functions

enrich_site_info(Hook, Prio)
-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.

run_level(Hook, Prio)
-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.

pre_autocluster(Hook, Prio)
-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.

pre_autoclean(Hook, Prio)
-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.

post_kick(Hook, Prio)
-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.

pre_kick(Hook, Prio)
-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.

post_join(Hook, Prio)
-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.

pre_join(Hook, Prio)
-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.

on_membership_change(Hook, Prio)
-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.

on_peer_connection_change(Hook, Prio)
-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.

on_create_site(Hook, Prio)
-spec on_create_site(fun((site()) -> _),
                     classy_hook:prio()) -> classy_hook:hook().

This callback is called once per site.

on_create_cluster(Hook, Prio)
-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.

on_node_init(Hook, Prio)
-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.

fault_tolerance(N)

Calculate how many nodes can be down while cluster still can maintain quorum.

quorum/1
-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)
at_lower_level(RunLevel, Fun)
-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.

nodes(Query)
-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.

sites()
-spec sites() -> [site()].

List IDs of peer sites.

kick_node(Node, Intent)
-spec kick_node(node(), kick_intent()) -> ok |
                                          {error, _}.

Translate node name to a site ID and kick it via classy:kick_site/2.

kick_site(Site, Intent)
-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:

  1. classy:pre_kick/2. It can decide that removing a site is unsafe and abort the command.
  2. classy:post_kick/2. This hook is executed after the target is successfully kicked.

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.

join_node(Node, Intent)
-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:

  1. Name of a node to join.

    Note: while the majority of classy APIs work with site IDs, joining a cluster is always done via regular Erlang node name.

  2. Join intent, see join_intent()
node_of_site(Site, OnlyConnected)
-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).

info(Nodes)
-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().

info()
-spec info() -> info().

Provide general information about the local node.


JavaScript license information