Behaviour and DSL for defining specifications through labelled transition systems (LTSs).
A specification module describes the expected states, actions, and transitions of a system. Spex uses this information to:
- validate observed runtime behaviour,
- construct and maintain implementation models,
- check branching bisimilarity between model and specification,
- enforce transition timeout and pruning policies.
This module provides:
- behaviour callbacks that every specification must implement,
- a
usemacro that generates those callbacks from a concise DSL, def_transition/3for declaring transitions,- default error handling that can be overridden per specification.
Configuration Options
Pass options to use Spex.Specification, ....
:transition_timeout
Maximum time between two observed transitions for an instance.
- Default:
:infinity - Accepted values:
:infinity, integer milliseconds, or%Duration{}(converted viato_timeout/1) - Used by instance manager timeout checks.
If an instance exceeds this timeout, Spex emits
%Spex.Errors.TransitionError{reason: :transition_timeout} and routes it
through the specification error_handler/2.
:prune_timeout
Minimum idle time before an instance can be considered for pruning.
- Default:
:infinity - Accepted values:
:infinity, integer milliseconds, or%Duration{}(converted viato_timeout/1)
Pruning eligibility also depends on :prunable_states.
:prunable_states
Controls which states are allowed to be pruned after :prune_timeout.
- Default:
[](no states are prunable) - Accepted values:
:all: any current state may be pruned:terminal: only terminal states may be pruned- explicit state list, e.g.
[:done, :failed]
Terminal states are derived from transitions as states with no outgoing edge.
Transition DSL
Define transitions with def_transition(from_state, action, to_state).
Each call contributes to compile-time metadata used to generate:
states/0actions/0transitions/0initial_state/0terminal_states/0
Duplicate states/actions/transitions are deduplicated.
The initial state is the source state of the first declared transition.
If no transitions are declared, initial_state/0 returns nil.
Generated Callbacks
When you use Spex.Specification, the following callbacks are generated
automatically:
transition_timeout/0prune_timeout/0prunable_states/0states/0actions/0transitions/0initial_state/0terminal_states/0error_handler/2(delegates todefault_error_handler/2by default)
error_handler/2 is overridable.
Error Handling Contract
error_handler/2 receives (error, caller_pid) and must return:
:okto swallow/accept the error condition, or{:error, reason}to propagate failure.
Default behaviour in default_error_handler/2:
- logs the error and caller stacktrace,
- returns
:okfor:%Spex.Errors.TransitionError{reason: :deviation_still_bisimilar}%Spex.Errors.ImplModelError{reason: :impl_model_not_found}
- returns
{:error, error}for all other errors.
Full Example
defmodule MySpec do
use Spex.Specification,
transition_timeout: 30_000,
prune_timeout: %Duration{hour: 1},
prunable_states: :terminal
def_transition :idle, :start, :running
def_transition :running, :complete, :done
def_transition :running, :fail, :failed
@impl Spex.Specification
def error_handler(error, caller) do
send(caller, {:spec_error, error})
{:error, error}
end
end
Summary
Callbacks
Callback for handling errors emitted by Spex during instance management.
Functions
Defines a transition from one state to another via an action.
Default error handling strategy used by specification modules.
Types
@type error_handler_return() :: :ok | {:error, Exception.t() | term()}
The return type for error_handler/2 callbacks.
@type t() :: module()
A module implementing this behaviour
Callbacks
@callback error_handler(handled_error(), caller_process :: pid()) :: error_handler_return()
Callback for handling errors emitted by Spex during instance management.
Functions
Defines a transition from one state to another via an action.
The first state of the first transition becomes the initial state. States and actions are automatically collected and deduplicated.
Example
def_transition :idle, :start, :working
def_transition :working, :complete, :idle
@spec default_error_handler(handled_error(), caller_process :: pid()) :: error_handler_return()
Default error handling strategy used by specification modules.