Module jhn_fsm

This is a generic FSM in the spirit of OTP's gen_fsm but subtly different.

Copyright © (C) 2013-2024, Jan Henry Nystrom <JanHenryNystrom@gmail.com> -------------------------------------------------------------------

Behaviours: jhn_server.

This module defines the jhn_fsm behaviour.
Required callback functions: init/1.
Optional callback functions: event/3, message/3, terminate/3, code_change/4, format_status/2.

Authors: Jan Henry Nystrom (JanHenryNystrom@gmail.com).

Description

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. En event/messages 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 has not a matching clause in the appropriate StateName/2 event/3or 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. !

Data Types

from()

from() = jhn_server:from()

fsm_ref()

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

init_return()

init_return(State) = ignore | return(State)

opt()

opt() = {atom(), term()}

opts()

opts() = [opt()]

return()

return(State) = {ok, atom(), State} | {hibernate, atom(), State} | {stop, atom()}

Function Index

call/2 A call is made to FSM with default timeout 5000ms.
call/3 A call is made to FSM with Timeout.
cancel/1 A timer a timer started using delayed_event/2, returns time remaining or false.
cast/2 An event is sent to the FSM, always retuns ok.
create/1 Creates a jhn_fsm.
create/2 Creates a jhn_fsm with options.
delayed_cast/2 An event is sent to the calling FSM after Delay ms, always returns a timer reference that can be canceled using cancel/1.
from/0 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/1 Called inside callback function to provide reply to a call.
reply/2 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/1 A synchronization is made with FSM with default timeout 5000ms.
sync/2 A synchronization is made with FSM with Timeout.
type/0 Called inside a state function or event/2 and it tells if it is a call or a cast.

Function Details

call/2

call(FSM::fsm_ref(), Msg::term()) -> term()

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

call/3

call(FSM::fsm_ref(), Event::term(), Timeout::timeout()) -> term()

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/1

cancel(Ref::reference()) -> non_neg_integer() | false

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

cast/2

cast(FSM::fsm_ref(), Event::term()) -> ok

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

create/1

create(Mod::atom()) -> {ok, pid()} | ignore | {error, term()}

Creates a jhn_fsm.

create/2

create(Mod::atom(), Opts::opts()) -> {ok, pid()} | ignore | {error, term()}

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/2

delayed_cast(Time::non_neg_integer(), Event::term()) -> 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/0

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/1

reply(Msg::term()) -> ok

Called inside callback function to provide reply to a call.

reply/2

reply(From::from(), Msg::term()) -> 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/1

sync(FSM::fsm_ref()) -> ok

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

sync/2

sync(FSM::fsm_ref(), Timeout::timeout()) -> term()

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/0

type() -> call | cast

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


Generated by EDoc