Module: Jongleur::Implementation Private

Defined in:
lib/jongleur/implementation.rb

Overview

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

this module encapsulates methods that are not meant to be accessed by the gem’s client callers and are used by the API module to implement functionality

See Also:

Class Method Summary collapse

Class Method Details

.all_predecessors_finished_successfully?(task_name) ⇒ Boolean

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:

  • (Boolean)


81
82
83
# File 'lib/jongleur/implementation.rb', line 81

def self.all_predecessors_finished_successfully?(task_name)
  get_predecessors(task_name).reduce(0) { |sum, t| sum + get_exit_status(t) }.zero?
end

.are_predecessors_running?(task_name) ⇒ Boolean

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:

  • (Boolean)


77
78
79
# File 'lib/jongleur/implementation.rb', line 77

def self.are_predecessors_running?(task_name)
  !get_predecessors(task_name).select(&:running).empty?
end

.build_task_matrix(task_graph) ⇒ Array

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.

Creates a list of tasks and their current state

Parameters:

  • task_graph (Hash)

Returns:

  • (Array)

    task_matrix a list of Tasks

See Also:



18
19
20
21
22
23
24
25
26
27
# File 'lib/jongleur/implementation.rb', line 18

def self.build_task_matrix(task_graph)
  return [] if task_graph.empty?
  # create it as a Set so we can easily ensure unique entries
  task_matrix = Set.new
  task_graph.keys.each { |t| task_matrix << Task.new(t, StatusCodes::PROCESS_NOT_YET_RAN, false) }
  task_graph.values.each do |val|
    val.each { |t| task_matrix << Task.new(t, StatusCodes::PROCESS_NOT_YET_RAN, false) }
  end
  task_matrix.to_a
end

.each_descendant(task) ⇒ 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.



155
156
157
158
159
160
161
# File 'lib/jongleur/implementation.rb', line 155

def self.each_descendant(task)
  API.task_graph[task]&.each do |desc_task|
    # check desc_task isn't already running and that its predecessors are finished
    yield find_task_by(:name, desc_task) if !task_running?(desc_task) &&
      finished_tasks.contains_array?(get_predecessors(desc_task))
  end
end

.find_task_by(attr_name, attr_value) {|Jongleur::Task| ... } ⇒ Jongleur::Task?

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.

Note:

the methof will find the first matching task. If there are more than one matches,

Find task based on an attribute’s value

only the first one -in sequence order- will be returned

Parameters:

  • attr_name (Symbol)
  • attr_value (Object)

    could be a String, Integer, Boolean, etc.

Yields:

Returns:

  • (Jongleur::Task, nil)

    the first task that matches the arguments, nil if no matches are found



149
150
151
152
153
# File 'lib/jongleur/implementation.rb', line 149

def self.find_task_by(attr_name, attr_value)
  idx = API.task_matrix.index { |t| t.send(attr_name.to_s) == attr_value }
  yield API.task_matrix[idx] if block_given? && idx
  idx ? API.task_matrix[idx] : nil
end

.finished_tasksObject

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.



128
129
130
# File 'lib/jongleur/implementation.rb', line 128

def self.finished_tasks
  API.task_matrix.map { |t| t.name if t.running == false }.compact.extend(Helper)
end

.get_exit_status(task_name) ⇒ Integer

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.

Gets a task’s exit status

Parameters:

  • task_name (Symbol)

Returns:

  • (Integer)

    the task’s exit status or StatusCodes::TASK_NOT_IN_TASK_MATRIX

See Also:



72
73
74
75
# File 'lib/jongleur/implementation.rb', line 72

def self.get_exit_status(task_name)
  idx = API.task_matrix.index { |t| t.name == task_name }
  idx ? API.task_matrix[idx].exit_status : StatusCodes::TASK_NOT_IN_TASK_MATRIX
end

.get_predecessors(task) ⇒ Array

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.

Lists a task’s dependent tasks

Parameters:

  • task (Symbol)

Returns:

  • (Array)

    a list of the dependent task names for the given task



33
34
35
36
# File 'lib/jongleur/implementation.rb', line 33

def self.get_predecessors(task)
  return [] if API.task_graph.empty?
  API.task_graph.select { |_k, v| v.include?(task) }.keys
end

.get_process_id(task_name) ⇒ Integer

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.

Gets the process id of a task.

hasn’t been ran yet

Parameters:

  • task_name (Symbol)

Returns:

  • (Integer)

    the pid of the task or Jongleur::StatusCodes::PROCESS_NOT_YET_RAN if the task



57
58
59
60
61
62
63
64
65
# File 'lib/jongleur/implementation.rb', line 57

def self.get_process_id(task_name)
  if valid_tasks?([].push(task_name))
    idx = API.task_matrix.index { |t| t.name == task_name }
    # STDOUT.puts ">>>>>  #{task_name} >>>>>> #{API.task_matrix[idx].pid}", "\n"
    API.task_matrix[idx].pid
  else
    StatusCodes::TASK_NOT_IN_TASK_GRAPH
  end
end

.get_task_listObject

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.



136
137
138
# File 'lib/jongleur/implementation.rb', line 136

def self.get_task_list
  API.task_matrix.select(&:running)
end

.parse_line(line) ⇒ Hash

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.

Parses a line of program output

Parameters:

  • a (String)

    line of program output

Returns:

  • (Hash)

    the output line in a key-value format



167
168
169
170
171
172
173
174
175
176
177
178
# File 'lib/jongleur/implementation.rb', line 167

def self.parse_line(line)
  res = {}
  msg_arr = []
  msg_arr = line.split(',') if line&.match(/^finished task/)
  msg_arr.each do |x|
    h = {}
    s = x.split(':')
    h[s.at(0).strip] = s.at(1).strip
    res.merge!(h)
  end
  res
end

.parse_output(string_io, print_to_stdout = false) ⇒ Array<Hash>

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.

Parses a multi-line string of program output

Parameters:

  • the (StringIO)

    standard output as a string

  • print (Boolean)

    output to stdout

Returns:

  • (Array<Hash>)

    a list of hashes representing the std output



186
187
188
189
190
191
192
193
194
# File 'lib/jongleur/implementation.rb', line 186

def self.parse_output(string_io, print_to_stdout = false)
  parsed = []
  string_io.each_line do |line|
    STDOUT.puts ">>> #{line}" if print_to_stdout
    line_as_hash = parse_line(line)
    parsed << line_as_hash unless line_as_hash.empty?
  end
  parsed
end

.predecessors_which_failed(task_name) ⇒ 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.



85
86
87
# File 'lib/jongleur/implementation.rb', line 85

def self.predecessors_which_failed(task_name)
  get_predecessors(task_name).select { |t| task_failed?(t) }
end

.predecessors_which_havent_finished(task_name) ⇒ 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.



89
90
91
# File 'lib/jongleur/implementation.rb', line 89

def self.predecessors_which_havent_finished(task_name)
  get_predecessors(task_name).reject { |t| task_finished?(t) }
end

.process_message(a_msg) ⇒ 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.



214
215
216
217
# File 'lib/jongleur/implementation.rb', line 214

def self.process_message(a_msg)
  STDOUT.puts(a_msg)
  STDOUT.sync
end

.run_descendants(task_name) ⇒ 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.

run all descendant tasks of given task



197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
# File 'lib/jongleur/implementation.rb', line 197

def self.run_descendants(task_name)
  each_descendant(task_name) do |t|
    waiting = predecessors_which_havent_finished(t.name)
    failed = predecessors_which_failed(t.name)

    if waiting.empty? && failed.empty?
      t.running = true
      Implementation.process_message "starting task #{t.name}"
      t.pid = fork { API.const_get(t.name).new(predecessors: get_predecessors(t.name)).execute }
    elsif !failed.empty?
      process_message "cannot start #{t.name} because its predecessor #{failed.first} failed to finish"
    elsif !waiting.empty?
      process_message "cannot start #{t.name} because its predecessor #{waiting.first} hasn't finished yet"
    end
  end
end

.running_tasksObject

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.



132
133
134
# File 'lib/jongleur/implementation.rb', line 132

def self.running_tasks
  API.task_matrix.select(&:running)
end

.task_failed?(task) ⇒ Boolean, Integer

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.

Check if a task has failed status

Returns:

  • (Boolean, Integer)

    true if task has a failed status, false if not, StatusCodes::TASK_NOT_IN_TASK_MATRIX if task not found



105
106
107
108
# File 'lib/jongleur/implementation.rb', line 105

def self.task_failed?(task)
  idx = API.task_matrix.index { |t| t.name == task }
  idx ? (API.task_matrix[idx].success_status == false) : StatusCodes::TASK_NOT_IN_TASK_MATRIX
end

.task_finished?(task) ⇒ Boolean, Integer

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.

Check if a task has finished running

Returns:

  • (Boolean, Integer)

    true if task has finished, false if not, StatusCodes::TASK_NOT_IN_TASK_MATRIX if task not found



123
124
125
126
# File 'lib/jongleur/implementation.rb', line 123

def self.task_finished?(task)
  idx = API.task_matrix.index { |t| t.name == task }
  idx ? API.task_matrix[idx].exit_status : StatusCodes::TASK_NOT_IN_TASK_MATRIX
end

.task_running?(task) ⇒ Boolean, Integer

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.

Check if a task is still tunning, at the time of checking

Returns:

  • (Boolean, Integer)

    true if task is running, false if not, StatusCodes::TASK_NOT_IN_TASK_MATRIX if task not found



114
115
116
117
# File 'lib/jongleur/implementation.rb', line 114

def self.task_running?(task)
  idx = API.task_matrix.index { |t| t.name == task }
  idx ? API.task_matrix[idx].running : StatusCodes::TASK_NOT_IN_TASK_MATRIX
end

.tasks_without_predecessorsArray

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.

Lists all tasks without dependents

Returns:

  • (Array)

    a list of all tasks without dependents



96
97
98
99
# File 'lib/jongleur/implementation.rb', line 96

def self.tasks_without_predecessors
  list = API.task_graph.keys - API.task_graph.values.flatten
  API.task_matrix.select { |t| list.include?(t.name) }
end

.valid_tasks?(task_list) ⇒ Boolean

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.

Note:

this method exists for the scenario where the user adds a task X to the Task Diagram but fails

Ensures a task, or list of tasks, are defined in the task_diagram and are loaded in Ruby. If #const_get can’t find the class it raises NameError. The method catches it and returns false

to provide an implementation of the Task’s class, i.e. class X < WorkerTask

Parameters:

  • tasks (Array<Symbol>)

    to be validated

Returns:

  • (Boolean)

    true if all tasks are valid, and false if one task or more are invalid



45
46
47
48
49
50
# File 'lib/jongleur/implementation.rb', line 45

def self.valid_tasks?(task_list)
  task_list.each { |task| API.const_get(task.to_s) }
  true
rescue NameError
  false
end