Statifier.StateMachine (statifier v1.9.0)

View Source

A GenServer wrapper around Statifier.StateChart for asynchronous state chart processing.

Using the StateMachine Macro

The use Statifier.StateMachine macro provides a convenient way to create StateMachine modules with callback support:

defmodule MyMachine do
  use Statifier.StateMachine, scxml: "my_machine.xml"

  def handle_state_enter(state_id, state_chart, _context) do
    Logger.info("Entered: #{state_id}")
  end

  def handle_send_action(target, event, data, _state_chart) do
    case target do
      "external_api" -> MyAPI.send(event, data)
      _ -> :ok
    end
  end
end

Macro Options

  • :scxml - SCXML file path or XML string (required)
  • :name - GenServer registration name
  • :snapshot_interval - Milliseconds between snapshot calls
  • :invoke_handlers - Map of invoke type to handler function for <invoke> elements

Manual Usage (without macro)

You can also use StateMachine directly without the macro:

Provides an OTP-compliant interface for running state charts as processes, with proper supervision support and clean separation from synchronous operations.

Usage

# Start from SCXML file
{:ok, pid} = Statifier.StateMachine.start_link("path/to/machine.xml")

# Start from SCXML string
{:ok, pid} = Statifier.StateMachine.start_link(xml_string)

# Send events asynchronously
Statifier.send(pid, "start_event")
Statifier.send(pid, "data_event", %{key: "value"})

# Query current state
active_states = Statifier.StateMachine.active_states(pid)

Comparison with Synchronous API

StateMachine provides asynchronous processing via GenServer:

  • Statifier.send(pid, event) - Asynchronous, fire-and-forget
  • Statifier.StateMachine.active_states(pid) - Synchronous query

For synchronous processing, use the existing direct API:

  • Statifier.send_sync(state_chart, event) - Returns updated state chart
  • Statifier.Configuration.active_leaf_states(config) - Direct access

Summary

Functions

Macro for creating StateMachine modules with callback support.

Get the current active leaf states.

Returns a specification to start this module under a supervisor.

Get the current StateChart (synchronous).

Send an event to the StateMachine asynchronously.

Start a StateMachine process.

Types

init_arg()

@type init_arg() :: String.t() | Statifier.StateChart.t()

t()

@type t() :: %Statifier.StateMachine{
  callback_module: module() | nil,
  snapshot_interval: non_neg_integer() | nil,
  snapshot_timer: reference() | nil,
  state_chart: Statifier.StateChart.t()
}

Functions

__using__(opts)

(macro)

Macro for creating StateMachine modules with callback support.

Options

  • :scxml - SCXML file path or XML string (required)
  • :name - GenServer registration name
  • :snapshot_interval - Milliseconds between snapshot calls

Generated Functions

The macro generates:

  • start_link/1 - Start the StateMachine GenServer
  • child_spec/1 - OTP child specification for supervisors
  • Default callback implementations from StateMachineBehaviour

active_states(server)

@spec active_states(GenServer.server()) :: MapSet.t(String.t())

Get the current active leaf states.

Returns a MapSet of currently active leaf state IDs.

child_spec(init_arg)

Returns a specification to start this module under a supervisor.

See Supervisor.

get_state_chart(server)

@spec get_state_chart(GenServer.server()) :: Statifier.StateChart.t()

Get the current StateChart (synchronous).

Useful for debugging or getting the complete state.

send_event(server, event_name, event_data \\ %{})

@spec send_event(GenServer.server(), String.t(), map()) :: :ok

Send an event to the StateMachine asynchronously.

The event is processed asynchronously and the StateMachine's internal state is updated. No return value is provided.

Examples

Statifier.StateMachine.send_event(pid, "start")
Statifier.StateMachine.send_event(pid, "data_received", %{payload: data})

start_link(init_arg, opts \\ [])

@spec start_link(
  init_arg(),
  keyword()
) :: GenServer.on_start()

Start a StateMachine process.

Arguments

  • init_arg - Can be:
    • SCXML file path (string ending in .xml)
    • SCXML string content (containing <scxml)
    • Pre-initialized StateChart

Options

  • :callback_module - Module implementing StateMachineBehaviour callbacks
  • :snapshot_interval - Interval for snapshot callbacks (milliseconds)
  • :log_level - Log level for state machine execution (:trace, :debug, :info, :warning, :error)
  • :log_adapter - Log adapter to use (defaults to environment-specific adapter)
  • Standard GenServer options (:name, :timeout, etc.)

Examples

{:ok, pid} = StateMachine.start_link("machine.xml")
{:ok, pid} = StateMachine.start_link(xml_string, name: :my_machine)