Search documentation of jhn_stdlib

# jhn_fsm behaviour (jhn_stdlib v5.10.3)

View Source

This is a generic FSM in the spirit of OTP's gen_fsm but subtly different. A generic server process (jhn_fsm) implemented using this module has a standard set of interface functions. It also fits into an OTP supervision tree and supports generic OTP tooling for, e.g., dynamic upgrades. The FSM can defer acting on incoming events messages to a later state, the defered events/messages are processed when a state-transition happen. The order of deferred events/messages are preserved. An event/message is only deferred when a callback function returns deferred.

A jhn_fsm process assumes all specific parts to be located in a callback module exporting a predefined set of functions, some optional.

The relationship between the behavior functions and the callback functions is as follows: ----->/-----> fuction call/return ====> message sent

User module jhn_fsm module Callback module

-----------------------------------------------------------------------

jhn_fsm:create/1/2 -----> proc_lib:spawn -----> init/1

jhn_fsm:create/1/2 <----- proc_lib:spawn <==== init/1

-----------------------------------------------------------------------

jhn_fsm:call/2/3 =====> (jhn_fsm) -----> StateName/2 or event/3

jhn_fsm:call/2/3 <===== (jhn_fsm) <----- jhn_fsm:reply/1/2 (optional)

-----------------------------------------------------------------------

jhn_fsm:sync/1/2 =====> (jhn_fsm)

jhn_fsm:sync/1/2 <===== (jhn_fsm)

-----------------------------------------------------------------------

jhn_fsm:cast/2/3 =====> (jhn_server) -----> StateName/2 or event/3

All the following are optional

Other process Callback module

-----------------------------------------------------------------------

Id ! Message =====> message/3

sys:terminate/2 =====> terminate/3

sys:code_change/4 =====> code_change/4

sys:get_status/2 =====> format_status/2

If a callback function fails or returns a bad value, the jhn_fsm process terminates. N.B. that a gen_fsm process does not trap exit signals automatically, this must be explicitly initiated in the callback module. The process is by default linked to the parent.

The event callback function is called when the state function for the does not have a matching clause for the incoming event, sent either by a call or cast, or the state function is undefined.

jhn_fsm supports hibernation. Any call, cast or plain message sent to the process that does not have a matching clause in the appropriate StateName/2 event/3 or messsage/2 call back function will be discarded and logged as unexpected. If the optional callback funtion message/2 is not defined there are no matching function clauses at all.

N.B. Recieving an event/message that is deferred will break hibernation, this may change in the future.

The callback module shall export:

init(Args) ==> {ok, StateName, State} | {hibernate, StateName, State} | ignore | {error, stop} | {stop, Reason} |

The callback module can export:

StateName(Msg, State) ==> {ok, StateName, State} | {hibernate, StateName, State} | deferred | {stop, Reason}

message(Msg, StateName, State) ==> {ok, StateName, State} | {hibernate, StateName, State} | deferred | {stop, Reason}

event(Msg, StateName, State) ==> {ok, StateName, State} | {hibernate, StateName, State} | deferred | {stop, Reason}

terminate(Reason, StateName, State) ==> Return value ignored

Lets the user module clean up always called when server terminates

code_change(OldVsn, StateName, Data, Extra) ==> {ok, State}

format_status(Opt, _) ==> {ok, State}

Uses the old format will be replaced. !

# Summary

## Types

event/0
from/0
fsm_ref/0
init_return/1
opts/0
return/1

## Callbacks

code_change/4
event/3
format_status/2
init/1
message/3
terminate/3

## Functions

call(FSM, Msg)

A call is made to FSM with default timeout 5000ms.

call(FSM, Event, Timeout)

A call is made to FSM with Timeout. Will generate a timeout exception if the FSM takes more than Timeout time to answer. Generates an exception if the process is dead, dies, or no process registered under that name. If the FSM returns that is returned from the call.

cancel(Ref)

A timer a timer started using delayed_event/2, returns time remaining or false.

cast(FSM, Event)

An event is sent to the FSM, always retuns ok.

create(Mod)

Creates a jhn_fsm.

create(Mod, Opts)

Creates a jhn_fsm with options. Options are: {link, Boolean} -> if the fsm is linked to the parent, default true {timeout, infinity | Integer} -> Time in ms for the fsm to create and initialise, after that an exception is generated, default 5000. {name, Atom} -> name that the fsm is registered under. {arg, Term} -> argument provided to the init/1 callback function, default is 'no_arg'.

delayed_cast(Time, Event)

An event is sent to the calling FSM after Delay ms, always returns a timer reference that can be canceled using cancel/1.

from()

Called inside a state function or event/3 callback function it will provide an opaque data data enables a reply to the call outside the scope of the callback function.

reply(Msg)

Called inside callback function to provide reply to a call.

reply(From, Msg)

Called by any process will send a reply to the one that sent the event to the fsm, the From argument is the result from a call to from/1 inside a state function or event/3 callback function.

sync(FSM)

A synchronization is made with FSM with default timeout 5000ms.

sync(FSM, Timeout)

A synchronization is made with FSM with Timeout. Will generate a timeout exception if the FSM takes more than Timeout time to answer. Generates an exception if the process is dead, dies, or no process registered under that name. If the fsm returns, ok is returned.

type()

Called inside a state function or event/2 and it tells if it is a call or a cast.

# Types

# event/0

    -type event() :: _.

# from/0

    -type from() :: jhn_server:from().

# fsm_ref/0

    -type fsm_ref() :: atom() | {atom(), node()} | pid().

# init_return/1

    -type init_return(State) :: ignore | return(State).

# opts/0

    -type opts() :: jhn_server:opts().

# return/1

    -type return(State) :: {ok, atom(), State} | {hibernate, atom(), State} | {stop, atom()}.

# Callbacks

# code_change/4

(optional)

    -callback code_change(_, atom(), State, _) -> return(State).

# event/3

(optional)

    -callback event(_, atom(), State) -> return(State).

# format_status/2

(optional)

    -callback format_status(_, _) -> _.

# init/1

    -callback init(State) -> init_return(State).

# message/3

(optional)

    -callback message(_, atom(), State) -> return(State).

# terminate/3

(optional)

    -callback terminate(_, atom(), _) -> _.

# Functions

# call(FSM, Msg)

    -spec call(fsm_ref(), _) -> _.

A call is made to FSM with default timeout 5000ms.

# call(FSM, Event, Timeout)

    -spec call(fsm_ref(), _, timeout()) -> _.

A call is made to FSM with Timeout. Will generate a timeout exception if the FSM takes more than Timeout time to answer. Generates an exception if the process is dead, dies, or no process registered under that name. If the FSM returns that is returned from the call.

# cancel(Ref)

    -spec cancel(reference()) -> non_neg_integer() | false.

A timer a timer started using delayed_event/2, returns time remaining or false.

# cast(FSM, Event)

    -spec cast(fsm_ref(), _) -> ok.

An event is sent to the FSM, always retuns ok.

# create(Mod)

    -spec create(atom()) -> {ok, pid()} | ignore | {error, _}.

Creates a jhn_fsm.

# create(Mod, Opts)

    -spec create(atom(), opts()) -> {ok, pid()} | ignore | {error, _}.

Creates a jhn_fsm with options. Options are: {link, Boolean} -> if the fsm is linked to the parent, default true {timeout, infinity | Integer} -> Time in ms for the fsm to create and initialise, after that an exception is generated, default 5000. {name, Atom} -> name that the fsm is registered under. {arg, Term} -> argument provided to the init/1 callback function, default is 'no_arg'.

# delayed_cast(Time, Event)

    -spec delayed_cast(non_neg_integer(), _) -> reference().

An event is sent to the calling FSM after Delay ms, always returns a timer reference that can be canceled using cancel/1.

# from()

    -spec from() -> from().

Called inside a state function or event/3 callback function it will provide an opaque data data enables a reply to the call outside the scope of the callback function.

# reply(Msg)

    -spec reply(_) -> ok.

Called inside callback function to provide reply to a call.

# reply(From, Msg)

    -spec reply(from(), _) -> ok.

Called by any process will send a reply to the one that sent the event to the fsm, the From argument is the result from a call to from/1 inside a state function or event/3 callback function.

# sync(FSM)

    -spec sync(fsm_ref()) -> ok.

A synchronization is made with FSM with default timeout 5000ms.

# sync(FSM, Timeout)

    -spec sync(fsm_ref(), timeout()) -> _.

A synchronization is made with FSM with Timeout. Will generate a timeout exception if the FSM takes more than Timeout time to answer. Generates an exception if the process is dead, dies, or no process registered under that name. If the fsm returns, ok is returned.

# type()

    -spec type() -> call | cast.

Called inside a state function or event/2 and it tells if it is a call or a cast.