Class: StatesLanguageMachine::Execution

Inherits:
Object
  • Object
show all
Defined in:
lib/ruby_slm/execution.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(state_machine, input = {}, name = nil, context = {}) ⇒ Execution

Returns a new instance of Execution.

Parameters:

  • state_machine (StateMachine)

    the state machine to execute

  • input (Hash) (defaults to: {})

    the input data for the execution

  • name (String, nil) (defaults to: nil)

    the name of the execution

  • context (Hash) (defaults to: {})

    additional context for the execution



39
40
41
42
43
44
45
46
47
48
49
50
51
# File 'lib/ruby_slm/execution.rb', line 39

def initialize(state_machine, input = {}, name = nil, context = {})
  @state_machine = state_machine
  @input = input.dup
  @name = name || "execution-#{Time.now.to_i}-#{SecureRandom.hex(4)}"
  @current_state = state_machine.start_state
  @output = input.dup
  @status = :running
  @history = []
  @logger = context[:logger]
  @context = context
  @start_time = Time.now
  @end_time = nil
end

Instance Attribute Details

#causeString?

Returns the cause of failure if execution failed.

Returns:

  • (String, nil)

    the cause of failure if execution failed



16
17
18
# File 'lib/ruby_slm/execution.rb', line 16

def cause
  @cause
end

#contextHash

Returns the execution context.

Returns:

  • (Hash)

    the execution context



22
23
24
# File 'lib/ruby_slm/execution.rb', line 22

def context
  @context
end

#current_stateString?

Returns the current state name.

Returns:

  • (String, nil)

    the current state name



8
9
10
# File 'lib/ruby_slm/execution.rb', line 8

def current_state
  @current_state
end

#end_timeTime?

Returns the execution end time.

Returns:

  • (Time, nil)

    the execution end time



24
25
26
# File 'lib/ruby_slm/execution.rb', line 24

def end_time
  @end_time
end

#errorString?

Returns the error type if execution failed.

Returns:

  • (String, nil)

    the error type if execution failed



14
15
16
# File 'lib/ruby_slm/execution.rb', line 14

def error
  @error
end

#historyArray<Hash>

Returns the execution history.

Returns:

  • (Array<Hash>)

    the execution history



18
19
20
# File 'lib/ruby_slm/execution.rb', line 18

def history
  @history
end

#inputHash (readonly)

Returns the original input data.

Returns:

  • (Hash)

    the original input data



29
30
31
# File 'lib/ruby_slm/execution.rb', line 29

def input
  @input
end

#loggerLogger?

Returns the logger for execution.

Returns:

  • (Logger, nil)

    the logger for execution



20
21
22
# File 'lib/ruby_slm/execution.rb', line 20

def logger
  @logger
end

#nameString (readonly)

Returns the execution name.

Returns:

  • (String)

    the execution name



31
32
33
# File 'lib/ruby_slm/execution.rb', line 31

def name
  @name
end

#outputHash

Returns the current output data.

Returns:

  • (Hash)

    the current output data



10
11
12
# File 'lib/ruby_slm/execution.rb', line 10

def output
  @output
end

#start_timeTime (readonly)

Returns the execution start time.

Returns:

  • (Time)

    the execution start time



33
34
35
# File 'lib/ruby_slm/execution.rb', line 33

def start_time
  @start_time
end

#state_machineStateMachine (readonly)

Returns the state machine being executed.

Returns:



27
28
29
# File 'lib/ruby_slm/execution.rb', line 27

def state_machine
  @state_machine
end

#statusSymbol

Returns the execution status (:running, :succeeded, :failed).

Returns:

  • (Symbol)

    the execution status (:running, :succeeded, :failed)



12
13
14
# File 'lib/ruby_slm/execution.rb', line 12

def status
  @status
end

Instance Method Details

#add_history_entry(state_name, output) ⇒ Object

Add an entry to the execution history

Parameters:

  • state_name (String)

    the name of the state that was executed

  • output (Hash)

    the output from the state execution



124
125
126
127
128
129
130
131
# File 'lib/ruby_slm/execution.rb', line 124

def add_history_entry(state_name, output)
  @history << {
    state_name: state_name,
    input: @output, # Current input before execution
    output: output,
    timestamp: Time.now
  }
end

#execution_timeFloat

Returns the total execution time in seconds.

Returns:

  • (Float)

    the total execution time in seconds



149
150
151
152
# File 'lib/ruby_slm/execution.rb', line 149

def execution_time
  return @end_time - @start_time if @end_time
  Time.now - @start_time
end

#failed?Boolean

Returns whether the execution failed.

Returns:

  • (Boolean)

    whether the execution failed



139
140
141
# File 'lib/ruby_slm/execution.rb', line 139

def failed?
  @status == :failed
end

#run_allExecution

Run the entire execution to completion

Returns:



55
56
57
58
59
60
# File 'lib/ruby_slm/execution.rb', line 55

def run_all
  while @status == :running && @current_state
    run_next
  end
  self
end

#run_nextExecution

Run the next state in the execution

Returns:



64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
# File 'lib/ruby_slm/execution.rb', line 64

def run_next
  return self unless @status == :running && @current_state

  state = @state_machine.get_state(@current_state)

  begin
    logger&.info("Executing state: #{@current_state}")

    # Execute the current state
    @output = state.execute(self, @output)

    # Check if the state set the execution to failed
    if @status == :failed
      logger&.info("Execution failed in state: #{@current_state}")
      @end_time ||= Time.now
      return self
    end

    # Determine next state - for choice states, we need to pass the output
    next_state = state.next_state_name(@output)

    logger&.info("State #{@current_state} completed. Next state: #{next_state}")

    if state.end_state?
      @status = :succeeded unless @status == :failed
      @current_state = nil
      @end_time = Time.now
      logger&.info("Execution completed successfully")
    elsif next_state
      @current_state = next_state
      logger&.info("Moving to next state: #{next_state}")
    else
      @status = :failed
      @error = "NoNextState"
      @cause = "State '#{@current_state}' has no next state and is not an end state"
      @end_time = Time.now
      logger&.error("Execution failed: #{@cause}")
    end

  rescue => e
    @status = :failed
    @error = e.is_a?(ExecutionError) ? e.cause : "ExecutionError"
    @cause = e.message
    @end_time = Time.now
    logger&.error("Execution failed in state #{@current_state}: #{e.message}")
    logger&.error(e.backtrace.join("\n")) if logger
  end

  self
end

#running?Boolean

Returns whether the execution is still running.

Returns:

  • (Boolean)

    whether the execution is still running



144
145
146
# File 'lib/ruby_slm/execution.rb', line 144

def running?
  @status == :running
end

#succeeded?Boolean

Returns whether the execution succeeded.

Returns:

  • (Boolean)

    whether the execution succeeded



134
135
136
# File 'lib/ruby_slm/execution.rb', line 134

def succeeded?
  @status == :succeeded
end

#to_hHash

Returns the execution details as a Hash.

Returns:

  • (Hash)

    the execution details as a Hash



155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
# File 'lib/ruby_slm/execution.rb', line 155

def to_h
  {
    name: @name,
    status: @status,
    current_state: @current_state,
    input: @input,
    output: @output,
    error: @error,
    cause: @cause,
    start_time: @start_time,
    end_time: @end_time,
    execution_time: execution_time,
    history: @history
  }
end

#to_jsonString

Returns the execution details as JSON.

Returns:

  • (String)

    the execution details as JSON



172
173
174
# File 'lib/ruby_slm/execution.rb', line 172

def to_json
  JSON.pretty_generate(to_h)
end

#update_output(new_output) ⇒ Object

Update the execution output

Parameters:

  • new_output (Hash)

    the new output data



117
118
119
# File 'lib/ruby_slm/execution.rb', line 117

def update_output(new_output)
  @output = new_output
end