Class: Phronomy::WorkflowRunner Private

Inherits:
Object
  • Object
show all
Includes:
Runnable
Defined in:
lib/phronomy/workflow_runner.rb

Overview

This class is part of a private API. You should avoid using this class if possible, as it may be removed or be changed in the future.

Execution boundary for compiled Workflows.

WorkflowRunner prepares WorkflowContext instances, registers FSMSession objects with the Runtime-owned EventLoop, observes completion, and persists serializable Workflow snapshots. All Workflow execution APIs share this path; their only differences are blocking and observation semantics.

Defined Under Namespace

Classes: Execution

Constant Summary collapse

FINISH =

This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.

:__end__

Instance Method Summary collapse

Methods included from Runnable

#batch, #trace

Constructor Details

#initialize(state_class:, entry_actions:, declared_states:, auto_transitions:, external_events:, entry_point:, exit_actions: {}, wait_state_names: [], state_store: nil) ⇒ WorkflowRunner

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns a new instance of WorkflowRunner.



27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
# File 'lib/phronomy/workflow_runner.rb', line 27

def initialize(
  state_class:,
  entry_actions:,
  declared_states:,
  auto_transitions:,
  external_events:,
  entry_point:,
  exit_actions: {},
  wait_state_names: [],
  state_store: nil
)
  @state_class = state_class
  @entry_actions = entry_actions
  @declared_states = declared_states
  @auto_state_set = auto_transitions.each_with_object({}) do |transition, set|
    set[transition[:from]] = true
  end
  @external_events = external_events
  @entry_point = entry_point
  @wait_state_names = wait_state_names
  @state_store = state_store
  @phase_machine_class = Workflow::PhaseMachineBuilder.new(
    entry_point: @entry_point,
    declared_states: @declared_states,
    wait_state_names: @wait_state_names,
    external_events: @external_events,
    entry_actions: @entry_actions,
    auto_transitions: auto_transitions,
    exit_actions: exit_actions
  ).build
end

Instance Method Details

#invoke(input, config: {}) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



59
60
61
62
63
64
65
66
67
68
69
70
# File 'lib/phronomy/workflow_runner.rb', line 59

def invoke(input, config: {})
  ensure_blocking_call_allowed!(:invoke, :invoke_async)
  caller_meta = {}
  caller_meta[:user_id] = config[:user_id] if config[:user_id]
  caller_meta[:session_id] = config[:session_id] if config[:session_id]

  trace("workflow.invoke", input: input.inspect, **caller_meta) do |_span|
    execution = prepare_new_execution(input, config)
    result = start_execution(execution).wait_result
    [result, nil]
  end
end

#invoke_deferred(input, config: {}) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



72
73
74
75
76
77
# File 'lib/phronomy/workflow_runner.rb', line 72

def invoke_deferred(input, config: {})
  execution = prepare_new_execution(input, config)
  start_execution(execution)
rescue => error
  failed_task("workflow-async:preparation", error)
end

#resume(state:, input: nil) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



90
91
92
# File 'lib/phronomy/workflow_runner.rb', line 90

def resume(state:, input: nil)
  send_event(state: state, event: :resume, input: input)
end

#send_event(state:, event:, input: nil) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
# File 'lib/phronomy/workflow_runner.rb', line 94

def send_event(state:, event:, input: nil)
  ensure_blocking_call_allowed!(:send_event, :signal)
  context = input ? state.merge(input) : state
  current_phase = context.phase.to_sym
  event_name = resolve_resume_event(current_phase, event)
  thread_id = context.thread_id
  unless thread_id
    raise ArgumentError, "Halted WorkflowContext has no thread_id"
  end

  execution = Execution.new(
    context: context,
    thread_id: thread_id.to_s,
    recursion_limit: Phronomy.configuration.recursion_limit,
    store: configured_store,
    persist: true
  )
  start_execution(
    execution,
    resume_event: event_name,
    resume_phase: current_phase
  ).wait_result
end

#signal(thread_id:, event:, payload: nil) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Posts an application-defined event to a currently live Workflow session.

Admission is asynchronous. A true result means the EventLoop accepted the event for an admitted session; it does not mean that a transition matched. A false result means that the Runtime is stopping or the session is no longer admitted.



124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
# File 'lib/phronomy/workflow_runner.rb', line 124

def signal(thread_id:, event:, payload: nil)
  if thread_id.nil?
    raise ArgumentError, "thread_id is required"
  end

  event_name = event.to_sym
  unless @external_events.key?(event_name)
    raise ArgumentError,
      "Unknown event #{event_name.inspect}. " \
      "Valid events: #{@external_events.keys.inspect}"
  end

  Phronomy::Runtime.instance.event_loop.post_to_session(
    Phronomy::Event.new(
      type: event_name,
      target_id: thread_id.to_s,
      payload: payload
    )
  )
end

#stream(input, config: {}, &observer) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Raises:

  • (ArgumentError)


79
80
81
82
83
84
85
86
87
88
# File 'lib/phronomy/workflow_runner.rb', line 79

def stream(input, config: {}, &observer)
  ensure_blocking_call_allowed!(:stream, :invoke_async)
  raise ArgumentError, "stream requires a block" unless observer

  execution = prepare_new_execution(input, config)
  start_execution(
    execution,
    stable_observer: observer
  ).wait_result
end