# Module ra_machine

- Description
- Data Types
- Function Index
- Function Details

The `ra_machine` behaviour.

## Description

The `ra_machine` behaviour.

Used to implement the logic for the state machine running inside Ra.

### Callbacks

`-callback init(Conf :: `machine_init_args()`) -> state()'`

Initialize a new machine state.

`-callback apply(Meta :: command_meta_data(), `command()`, State) -> {State, `reply()`, `effects()`} | {State, `reply()`}`

Applies each entry to the state machine.

`-callback state_enter(ra_server:ra_state() | eol, state()) -> effects().`

Optional. Called when the ra server enters a new state. Called for all states in the ra_server_proc gen_statem implementation not just for the standard Raft states (follower, candidate, leader). If implemented it is sensible to include a catch all clause as new states may be implemented in the future.

`-callback tick(TimeMs :: milliseconds(), state()) -> effects().`

Optional. Called periodically. Suitable for issuing periodic side effects such as updating metrics systems.

`-callback overview(state()) -> map().`

Optional. A map of overview information. Needs to be efficient.

## Data Types

### builtin_command()

    builtin_command() =
        {down, pid(), term()} | {nodeup | nodedown, node()} | timeout

These commands may be passed to the `apply/2` function in reaction to monitor effects

### command()

    command() = user_command() | builtin_command()

### command_meta_data()

    command_meta_data() =
        #{system_time := integer(),
          index := ra_index(),
          term := ra_term()}

extensible command meta data map

### effect()

    effect() =
        {send_msg, To :: locator(), Msg :: term()} |
        {send_msg,
         To :: locator(),
         Msg :: term(),
         Options :: send_msg_opts()} |
        {mod_call, module(), Function :: atom(), [term()]} |
        {monitor, process, pid()} |
        {monitor, node, node()} |
        {demonitor, process, pid()} |
        {demonitor, node, node()} |
        {timer, non_neg_integer() | infinity} |
        {log, ra_index(), fun((term()) -> maybe(effect()))} |
        {release_cursor, ra_index(), state()} |
        {aux, term()} |
        garbage_collection

Effects are data structure that can be returned by `apply/3` to ask ra to realise a side-effect in the real works, such as sending a message to a process.

Although both leaders and followers will process the same commands effects are typically only applied on the leader. The only exceptions to this are the `relaase_cursor` effect that is realised on all effects as it is part of the ra implementation log truncation mechanism and the `garbage_collect` effects that is used to explicitly triggering a garbage collection in the ra servers's process.

When leaders change and when clusters are restarted there is a small chance that effects are issued multiple times so designing effects to be idempotent is a good idea.

send_msg
  send a message to a pid or registered process NB: this is sent using `noconnect` and `nosuspend` in order to avoid blocking the ra process during failures. It can optionally be wrapped up as a `ra_event` and/or as a gen cast message (`{'$cast', Msg}`)
mod_call
  Call an arbitrary Module:Function with the supplied arguments
monitor
  monitor a process or erlang node
demonitor
  demonitor a process or erlang node
release_cursor
  indicate to Ra that none of the preceeding entries contribute to the current machine state

### effects()

    effects() = [effect()]

See: `effect`

### locator()

    locator() = pid() | atom() | {atom(), node()}

### machine()

    machine() =
        {machine, module(), AddInitArgs :: #{term() => term()}}

Machine configuration. the `module()` should implement the `ra_machine` behaviour.

### milliseconds()

    milliseconds() = non_neg_integer()

### reply()

    reply() = term()

an arbitrary term that can be returned to the caller, _if_ the caller used `ra:process_command/2` or `ra:process_command/3`

### send_msg_opt()

    send_msg_opt() = [ra_event | cast] | ra_event | cast

ra_event: the message will be wrapped up and sent as a ra event e.g: `{ra_event, ra_server_id(), Msg}`

cast: the message will be wrapped as a gen cast: `{'$cast', Msg}`

### send_msg_opts()

    send_msg_opts() = send_msg_opt() | [send_msg_opt()]

### state()

    state() = term()

The state for a given machine implementation.

### user_command()

    user_command() = term()

the command type for a given machine implementation

## Function Index

init/2 | initialise a new machine.
apply/4 |
tick/3 |
state_enter/3 | called when the ra_server_proc enters a new state.
overview/2 |
init_aux/2 |
handle_aux/7 |
query/3 |
module/1 |
snapshot_module/1 |

## Function Details

### init/2

    init(X1 :: machine(), Name :: atom()) -> state()

initialise a new machine

### apply/4

    apply(X1 :: machine(),
          Metadata :: command_meta_data(),
          Cmd :: command(),
          State) ->
             {State, reply(), effects()} | {State, reply()}

### tick/3

    tick(X1 :: machine(), TimeMs :: milliseconds(), State :: state()) ->
            effects()

### state_enter/3

    state_enter(X1 :: machine(),
                RaftState :: ra_server:ra_state() | eol,
                State :: state()) ->
                   effects()

called when the ra_server_proc enters a new state

### overview/2

    overview(X1 :: machine(), State :: state()) -> map()

### init_aux/2

    init_aux(X1 :: machine(), Name :: atom()) -> term()

### handle_aux/7

    handle_aux(X1 :: machine(),
               RaftState :: ra_server:ra_state(),
               Type :: {call, From :: from()} | cast,
               Command :: term(),
               AuxState,
               LogState,
               MacState :: state()) ->
                  {reply, Reply :: term(), AuxState, LogState} |
                  {no_reply, AuxState, LogState} |
                  undefined

-     AuxState = term()

-     LogState = ra_log:ra_log()

### query/3

    query(Mod :: module(),
          Fun :: fun((state()) -> Result),
          State :: state()) ->
             Result

-     Result = term()

### module/1

    module(X1 :: machine()) -> module()

### snapshot_module/1

    snapshot_module(X1 :: machine()) -> module()

Generated by EDoc