classy_vote ¶This module implements a variation of 2-phase commit.
Important to note:
This API uses both synchronous and asynchronous methods of status and error reporting.
Both methods must be handled in all cases.
Note: when create/1 API returns {ok, _},
it doesn’t mean the commit has been completed.
{ok, _},
it means commit flow entered "persistent" path.
Persistent path continues even after restart of any involved site.
Because of that, it uses asynchronous method of status reporting
via callbacks passed in the options.
The coordinator is notified of the outcome via post_vote callback.
The participants are notified via their respective commit or rollback callbacks.
post_vote, commit or rollback callbacks throw an exception,
on_fail callback gets involved.
Such mechanism is used because classy doesn’t automatically retry any actions that failed on the persistent path:
there is a high risk that these actions will just keep failing repeatedly.
Instead, they are abandoned until the next node restart.
on_fail callback provides a mechanism to signal such failures back to the business logic.
-type vote_info() :: #{tag := tag(), id := id(),
role := coordinator | participant, _ => _}.
-type fail_info() :: #{tag := tag(), id := id(),
reason := _, _ => _}.
-type outcome() :: #c_outcome{}.
-type vote() :: #c_vote{}.
-type options() :: #{tag := tag(),
actions := #{classy:site() => actions()},
post_vote => classy_lib:mfargs(),
strategy => strategy(), on_fail => classy_lib:mfargs()}.
Common vote options.
tagAn arbitrary tag identifying the commit action. Ongoing commit actions can be efficiently filtered by the tag.
actionsA map from site ID to per-site commit actions. Each site in the map becomes a vote participant. Participants’ actions may be non-uniform.
post_voteCallback that is executed on the coordinator after the decision is made. Classy prepends two arguments to the user-specified argument list:
The return value is ignored.
Note: it’s NOT guaranteed that all commit actions on the participants are finished
by the time when post_vote is called.
This callback can be retried on node restart.
strategySee strategy().
on_failExecuted on both coordinator and participant if commit / rollback / post_commit actions fail. This callback may be used to signal failures to the business logic. Classy prepends an argument of type t:classy_vote:fail_info/0 to the user-specified argument list.
-type actions() :: #{prepare := classy_lib:mfargs(),
commit := [classy_lib:mfargs()],
rollback => [classy_lib:mfargs()]}.
Per-participant set of commit actions.
prepareCallback that lets the participant decide whether to commit.
Classy prepends two additional values to the user-specified argument list:
false during pre-commit fast abort check
and to true during the persistent flow.
The return value is a boolean indicating the participant’s vote (true means “yes”).
commitList of actions executed on the sites if the coordinator decides to go ahead with the commit. Classy prepends vote ID to the user-specified argument list. Return value is ignored.
rollbackAction executed on the participant when the coordinator decides to abort the commit. Classy prepends vote ID to the user-specified argument list. Return value is ignored.
-type strategy() :: {all, timeout()}.
Strategy used to decide whether to commit.
all: All participant must vote yes within the timeout.
-type id() :: classy_uid:cu_tuple().
Unique ID of the vote.
-type tag() :: term().
Arbitrary tag associated with the operation. It allows business logic to quickly enumerate ongoing votes of certain kind.
-spec create(options()) -> {ok, classy_vote:id()} |
{error, _}.
Initiate a new vote, see options/0.
-spec fold_ongoing(fun((vote_info(), Acc) -> Acc), Acc,
_TagMatchPattern) -> Acc.
Fold over ongoing 2PC flows where the local site is either a coordinator or a participant.
Arguments:
-spec ls_votes(_TagMatch) -> [vote_info()].
List all ongoing 2PC flows where the local site is either a coordinator or a participant.
The argument is an ETS match expression that allows to filter on the tag.
-spec ls_votes() -> [vote_info()].
See classy_vote:ls_votes/1. No filtering.