Class: RemoteRun::Runner

Inherits:
Object
  • Object
show all
Defined in:
lib/remote_run/runner.rb

Instance Method Summary collapse

Constructor Details

#initialize(configuration) ⇒ Runner

Returns a new instance of Runner.



3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# File 'lib/remote_run/runner.rb', line 3

def initialize(configuration)
  @configuration = configuration
  @results = []
  @children = []
  @failed = []
  @stty_config = `stty -g`
  @last_timestamp = Time.now.strftime("%S")[0]
  @hosts = []

  @task_manager = @configuration.task_manager
  @host_manager = @configuration.host_manager
  @starting_number_of_tasks = @task_manager.count
  @before_task = @configuration.before_task
  @after_task = @configuration.after_task
  @around_task = @configuration.around_task
end

Instance Method Details

#check_for_finishedObject



129
130
131
132
133
134
135
136
137
138
139
140
# File 'lib/remote_run/runner.rb', line 129

def check_for_finished
  @children.each do |task|
    child_pid = task.pid
    if task_is_finished?(child_pid)
      @results << $?.exitstatus
      if @results.last.to_s != "0"
        log("Below tasks failed on #{task.host.hostname}\n#{task.command}", :red)
      end
      @children.delete(task)
    end
  end
end

#display_logObject



146
147
148
149
150
151
152
153
154
# File 'lib/remote_run/runner.rb', line 146

def display_log
  now = Time.now.strftime("%M")[0]
  unless now == @last_timestamp
    log("Waiting on #{@task_manager.count} of #{@starting_number_of_tasks} tasks to start.") if @task_manager.count > 0
    log("Waiting on #{@children.length} of #{@starting_number_of_tasks - @task_manager.count} started tasks to finish. #{@failed.size} failed.") if @children.length > 0
    $stdout.flush
    @last_timestamp = now
  end
end

#find_lock_and_startObject



105
106
107
108
109
110
111
112
113
# File 'lib/remote_run/runner.rb', line 105

def find_lock_and_start
  @hosts = @host_manager.hosts.dup if @hosts.empty?
  if host = @hosts.sample
    @hosts.delete(host)
    if host.lock
      start_task(host)
    end
  end
end

#handle_resultsObject



65
66
67
68
69
70
71
72
73
74
75
76
77
# File 'lib/remote_run/runner.rb', line 65

def handle_results
  failed_tasks = @results.select { |result| result != 0 }
  status_code = if failed_tasks.length == 0
    log("Task passed.", :green)
    Host::PASS
  else
    log("#{failed_tasks.length} task(s) failed.", :red)
    Host::FAIL
  end

  log("Total Time: #{run_time} minutes.")
  status_code
end

#log(message, color = :yellow) ⇒ Object



121
122
123
124
125
126
127
# File 'lib/remote_run/runner.rb', line 121

def log(message, color = :yellow)
  unless @configuration.quiet
    highline = HighLine.new
    system("stty #{@stty_config} 2>/dev/null")
    highline.say(highline.color("[Remote :: #{@configuration.identifier} :: #{run_time}] #{message}", color))
  end
end

#runObject



20
21
22
23
24
25
26
# File 'lib/remote_run/runner.rb', line 20

def run
  setup_unlock_on_exit
  sync_working_copy_to_temp_location
  start_tasks
  wait_for_tasks_to_finish
  handle_results
end

#run_timeObject



115
116
117
118
119
# File 'lib/remote_run/runner.rb', line 115

def run_time
  minutes = ((Time.now - @configuration.start_time) / 60).to_i
  seconds = ((Time.now - @configuration.start_time) % 60).to_i
  "#{minutes}:#{"%02d" % seconds}"
end

#setup_unlock_on_exitObject



28
29
30
31
32
33
34
35
36
37
# File 'lib/remote_run/runner.rb', line 28

def setup_unlock_on_exit
  at_exit do
    @configuration.hosts.each do |host|
      begin
        host.unlock
      rescue Errno::EPIPE
      end
    end
  end
end

#start_forked_task(host, task) ⇒ Object



88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
# File 'lib/remote_run/runner.rb', line 88

def start_forked_task(host, task)
  begin
    @before_task.call(host, task, self)
    this_host = host.dup
    unless this_host.copy_codebase
      @task_manager.add(task)
      status = 0
    end
    @around_task.call { status = this_host.run(task.command) }
    host.unlock
  rescue Errno::EPIPE
  ensure
    @after_task.call(host, task, self)
    Process.exit!(status)
  end
end

#start_task(host) ⇒ Object



79
80
81
82
83
84
85
86
# File 'lib/remote_run/runner.rb', line 79

def start_task(host)
  task = @task_manager.find_task
  task.pid = fork do
    start_forked_task(host, task)
  end
  task.host = host
  @children << task
end

#start_tasksObject



46
47
48
49
50
51
52
53
54
55
56
# File 'lib/remote_run/runner.rb', line 46

def start_tasks
  log("Starting tasks... #{Time.now}")

  while @task_manager.has_more_tasks?
    display_log
    check_for_finished
    find_lock_and_start
  end

  log("All tasks started... #{Time.now}")
end

#sync_working_copy_to_temp_locationObject



39
40
41
42
43
44
# File 'lib/remote_run/runner.rb', line 39

def sync_working_copy_to_temp_location
  log("Creating temporary copy of #{@configuration.local_path} in #{@configuration.temp_path}...")
  excludes = @configuration.exclude.map { |dir| "--exclude '#{dir}'"}
  system("rsync #{@configuration.rsync_options} --delete-excluded #{excludes.join(" ")} -q #{@configuration.local_path}/ #{@configuration.temp_path}/")
  log("Done.")
end

#task_is_finished?(pid) ⇒ Boolean

Returns:

  • (Boolean)


142
143
144
# File 'lib/remote_run/runner.rb', line 142

def task_is_finished?(pid)
  Process.waitpid(pid, Process::WNOHANG)
end

#wait_for_tasks_to_finishObject



58
59
60
61
62
63
# File 'lib/remote_run/runner.rb', line 58

def wait_for_tasks_to_finish
  while @children.length > 0
    display_log
    check_for_finished
  end
end