Class: Taski::Execution::ExecutionFacade

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

Overview

Central hub for execution events — provides both Pull (query) and Push (observer notification) interfaces. Holds only construction-time config plus observer/capture plumbing; no mutable domain state.

Events (in order): ready, start, task_updated, group_started, group_completed, stop.

All observer operations are synchronized using Monitor.

Constant Summary collapse

THREAD_LOCAL_KEY =
:taski_execution_context

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(root_task_class:) ⇒ ExecutionFacade

Returns a new instance of ExecutionFacade.



21
22
23
24
25
26
27
28
# File 'lib/taski/execution/execution_facade.rb', line 21

def initialize(root_task_class:)
  @root_task_class = root_task_class
  @dependency_graph = StaticAnalysis::DependencyGraph.new.build_from_cached(root_task_class).freeze
  @monitor = Monitor.new
  @observers = []
  @output_capture = nil
  @original_stdout = nil
end

Instance Attribute Details

#dependency_graphObject (readonly)

Returns the value of attribute dependency_graph.



19
20
21
# File 'lib/taski/execution/execution_facade.rb', line 19

def dependency_graph
  @dependency_graph
end

#root_task_classObject (readonly)

Returns the value of attribute root_task_class.



19
20
21
# File 'lib/taski/execution/execution_facade.rb', line 19

def root_task_class
  @root_task_class
end

Class Method Details

.build_default(root_task_class:) ⇒ Object

Build a facade with the global progress observer attached.



31
32
33
34
35
36
# File 'lib/taski/execution/execution_facade.rb', line 31

def self.build_default(root_task_class:)
  facade = new(root_task_class: root_task_class)
  progress = Taski.progress_display
  facade.add_observer(progress) if progress
  facade
end

.currentObject



38
39
40
# File 'lib/taski/execution/execution_facade.rb', line 38

def self.current
  Thread.current[THREAD_LOCAL_KEY]
end

.current=(context) ⇒ Object



42
43
44
# File 'lib/taski/execution/execution_facade.rb', line 42

def self.current=(context)
  Thread.current[THREAD_LOCAL_KEY] = context
end

Instance Method Details

#add_observer(observer) ⇒ Object



99
100
101
102
# File 'lib/taski/execution/execution_facade.rb', line 99

def add_observer(observer)
  @monitor.synchronize { @observers << observer }
  observer.context = self if observer.respond_to?(:context=)
end

#notify_group_completed(task_class, group_name, phase:, timestamp:) ⇒ Object



126
127
128
# File 'lib/taski/execution/execution_facade.rb', line 126

def notify_group_completed(task_class, group_name, phase:, timestamp:)
  dispatch(:on_group_completed, task_class, group_name, phase: phase, timestamp: timestamp)
end

#notify_group_started(task_class, group_name, phase:, timestamp:) ⇒ Object



122
123
124
# File 'lib/taski/execution/execution_facade.rb', line 122

def notify_group_started(task_class, group_name, phase:, timestamp:)
  dispatch(:on_group_started, task_class, group_name, phase: phase, timestamp: timestamp)
end

#notify_readyObject

Event notifications — dispatched to all registered observers.



114
# File 'lib/taski/execution/execution_facade.rb', line 114

def notify_ready = dispatch(:on_ready)

#notify_startObject



115
# File 'lib/taski/execution/execution_facade.rb', line 115

def notify_start = dispatch(:on_start)

#notify_stopObject



116
# File 'lib/taski/execution/execution_facade.rb', line 116

def notify_stop = dispatch(:on_stop)

#notify_task_updated(task_class, previous_state:, current_state:, phase:, timestamp:) ⇒ Object



118
119
120
# File 'lib/taski/execution/execution_facade.rb', line 118

def notify_task_updated(task_class, previous_state:, current_state:, phase:, timestamp:)
  dispatch(:on_task_updated, task_class, previous_state: previous_state, current_state: current_state, phase: phase, timestamp: timestamp)
end

#observersObject



108
109
110
# File 'lib/taski/execution/execution_facade.rb', line 108

def observers
  @monitor.synchronize { @observers.dup }
end

#original_stderrObject



54
55
56
# File 'lib/taski/execution/execution_facade.rb', line 54

def original_stderr
  @monitor.synchronize { @original_stderr }
end

#original_stdoutObject



50
51
52
# File 'lib/taski/execution/execution_facade.rb', line 50

def original_stdout
  @monitor.synchronize { @original_stdout }
end

#output_captureObject



85
86
87
# File 'lib/taski/execution/execution_facade.rb', line 85

def output_capture
  @monitor.synchronize { @output_capture }
end

#output_capture_active?Boolean

Returns:

  • (Boolean)


46
47
48
# File 'lib/taski/execution/execution_facade.rb', line 46

def output_capture_active?
  @monitor.synchronize { !@output_capture.nil? }
end

#remove_observer(observer) ⇒ Object



104
105
106
# File 'lib/taski/execution/execution_facade.rb', line 104

def remove_observer(observer)
  @monitor.synchronize { @observers.delete(observer) }
end

#setup_output_capture(output_io) ⇒ Object

Captures $stdout and $stderr using a TaskOutputRouter for inline progress display.



59
60
61
62
63
64
65
66
67
68
# File 'lib/taski/execution/execution_facade.rb', line 59

def setup_output_capture(output_io)
  @monitor.synchronize do
    @original_stdout = output_io
    @original_stderr = $stderr
    @output_capture = TaskOutputRouter.new(@original_stdout, self)
    @output_capture.start_polling
    $stdout = @output_capture
    $stderr = @output_capture
  end
end

#teardown_output_captureObject



70
71
72
73
74
75
76
77
78
79
80
81
82
83
# File 'lib/taski/execution/execution_facade.rb', line 70

def teardown_output_capture
  capture = nil
  @monitor.synchronize do
    return unless @original_stdout

    capture = @output_capture
    $stdout = @original_stdout
    $stderr = @original_stderr if @original_stderr
    @output_capture = nil
    @original_stdout = nil
    @original_stderr = nil
  end
  capture&.stop_polling
end

#trigger_clean(task_class, registry:) ⇒ Object



95
96
97
# File 'lib/taski/execution/execution_facade.rb', line 95

def trigger_clean(task_class, registry:)
  Executor.execute_clean(task_class, registry: registry, execution_facade: self)
end

#trigger_execution(task_class, registry:) ⇒ Object

Delegation to Executor — isolates TaskWrapper from direct Executor dependency.



91
92
93
# File 'lib/taski/execution/execution_facade.rb', line 91

def trigger_execution(task_class, registry:)
  Executor.execute(task_class, registry: registry, execution_facade: self)
end