Class: ExcADG::StateMachine
- Inherits:
-
Object
- Object
- ExcADG::StateMachine
- Defined in:
- lib/excadg/state_machine.rb
Overview
carry states and transitions for individual vertices
Defined Under Namespace
Classes: NotAllTransitionsBound, WrongState, WrongTransition
Constant Summary collapse
- GRAPH =
sets in stone possible state transitions
RGL::DirectedAdjacencyGraph.new
Instance Method Summary collapse
- #assert_state_transition_bounds ⇒ Object
-
#bind_action(source, target, &block) ⇒ Object
bind action to one of the state graph’s edges.
-
#initialize(name:) ⇒ StateMachine
constructor
add states graph to the current object.
-
#state_data ⇒ Object
makes state data for the current vertex.
-
#step ⇒ Object
transition to next state @return: state data (result) / nil if it’s a final step.
-
#with_fault_processing ⇒ Object
invoke the block provided with state update on failures.
Constructor Details
#initialize(name:) ⇒ StateMachine
add states graph to the current object
23 24 25 26 27 28 29 |
# File 'lib/excadg/state_machine.rb', line 23 def initialize name: @state = :new @state_edge_bindings = {} @state_transition_data = {} @name = name end |
Instance Method Details
#assert_state_transition_bounds ⇒ Object
83 84 85 |
# File 'lib/excadg/state_machine.rb', line 83 def assert_state_transition_bounds raise NotAllTransitionsBound, GRAPH.edges - @state_edge_bindings.keys unless GRAPH.edges.eql? @state_edge_bindings.keys end |
#bind_action(source, target, &block) ⇒ Object
bind action to one of the state graph’s edges
32 33 34 35 36 37 38 39 40 |
# File 'lib/excadg/state_machine.rb', line 32 def bind_action source, target, &block [source, target].each { |state| raise WrongState, "unknown state #{state}" unless GRAPH.has_vertex? state } raise WrongTransition.new source, target unless GRAPH.has_edge? source, target edge = GRAPH.edges.find { |e| e.source == source && e.target = target } @state_edge_bindings[edge] = block end |
#state_data ⇒ Object
makes state data for the current vertex
88 89 90 |
# File 'lib/excadg/state_machine.rb', line 88 def state_data VStateData::Full.new name: @name, data: @state_transition_data[@state], state: @state end |
#step ⇒ Object
transition to next state @return: state data (result) / nil if it’s a final step
44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 |
# File 'lib/excadg/state_machine.rb', line 44 def step Log.debug 'taking another step' assert_state_transition_bounds target_candidates = GRAPH.each_adjacent @state Log.debug "possible candidates: #{target_candidates.size}" return nil if target_candidates.none? raise WrongState, "state #{@state} has more than one adjacent states" unless target_candidates.one? target = target_candidates.first Log.debug "found a candidate: #{target}" edge = GRAPH.edges.find { |e| e.source == @state && e.target = target } with_fault_processing { Log.debug "calling payload for #{edge}" @state_transition_data[target] = @state_edge_bindings[edge].call @state = target Log.debug "moved to #{@state}" } @state_transition_data[@state] end |
#with_fault_processing ⇒ Object
invoke the block provided with state update on failures
67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 |
# File 'lib/excadg/state_machine.rb', line 67 def with_fault_processing yield if block_given? rescue StandardError => e Log.error "step failed with '#{e}' / #{e.backtrace}" @state_transition_data[:failed] = e @state = :failed ensure begin Broker.ask Request::Update.new data: state_data rescue StandardError => e @state_transition_data[:failed] = e @state = :failed Broker.ask Request::Update.new data: state_data end end |