Class: Autorespawn::Manager
- Inherits:
-
Object
- Object
- Autorespawn::Manager
- Includes:
- Hooks, Hooks::InstanceHooks
- Defined in:
- lib/autorespawn/manager.rb
Overview
Manager of a bunch of autorespawn slaves
Instance Attribute Summary collapse
-
#active_slaves ⇒ Hash<Slave>
readonly
List of active slaves.
-
#name ⇒ Object
readonly
An object that is used to identify the manager itself.
-
#parallel_level ⇒ Integer
readonly
The number of processes allowed to work in parallel.
-
#seed ⇒ ProgramID
readonly
A seed object that is passed to new slaves to represent the currently known state of file, to avoid unnecessary respawning.
-
#self_slave ⇒ Self
readonly
An object that has the same API than [Slave] to represent the manager’s process itself.
-
#workers ⇒ Array<Slave>
readonly
Declared worker processes, as a hash from the PID to a Slave object.
Hooks collapse
-
#on_slave_finished {|the| ... } ⇒ Object
Hook called when a slave finishes.
-
#on_slave_new(&block) {|the| ... } ⇒ Object
Register a callback for when a new slave is added by #add_slave.
-
#on_slave_removed {|the| ... } ⇒ Object
Hook called when a slave has been removed from this manager.
-
#on_slave_start(&block) {|the| ... } ⇒ Object
Register a callback that should be called when a new slave has been spawned by #poll.
Instance Method Summary collapse
-
#active?(slave) ⇒ Boolean
Tests whether this slave is currently active on self.
-
#add_slave(*cmdline, name: nil, **spawn_options) ⇒ Object
Spawns a worker, i.e.
-
#clear ⇒ Object
Kill and remove all workers from this manager.
-
#collect_finished_slaves(wait: false) ⇒ Array<Slave>
private
Collect information about the finished slaves.
-
#include?(slave) ⇒ Boolean
Tests whether this slave is registered as a worker on self.
-
#initialize(name: nil, parallel_level: 1) ⇒ Manager
constructor
A new instance of Manager.
-
#kill ⇒ Object
Kill all active slaves.
-
#poll ⇒ Object
Wait for children to terminate and spawns them when needed.
-
#register_seed_files(files, search_patch = seed.ruby_load_path, ignore_not_found: true) ⇒ Object
Add files to #seed.
-
#register_slave(slave) ⇒ Object
private
Registers a slave.
-
#remove_slave(slave) ⇒ Object
Remove a worker from this manager.
- #run ⇒ Object
Methods included from Hooks
Constructor Details
#initialize(name: nil, parallel_level: 1) ⇒ Manager
Returns a new instance of Manager.
70 71 72 73 74 75 76 77 78 79 |
# File 'lib/autorespawn/manager.rb', line 70 def initialize(name: nil, parallel_level: 1) @parallel_level = parallel_level + 1 @workers = Array.new @name = name @seed = ProgramID.for_self @self_slave = Self.new(name: name) @workers << self_slave @active_slaves = Hash[self_slave.pid => self_slave] end |
Instance Attribute Details
#active_slaves ⇒ Hash<Slave> (readonly)
Returns list of active slaves.
25 26 27 |
# File 'lib/autorespawn/manager.rb', line 25 def active_slaves @active_slaves end |
#name ⇒ Object (readonly)
Returns an object that is used to identify the manager itself.
14 15 16 |
# File 'lib/autorespawn/manager.rb', line 14 def name @name end |
#parallel_level ⇒ Integer (readonly)
Returns the number of processes allowed to work in parallel.
20 21 22 |
# File 'lib/autorespawn/manager.rb', line 20 def parallel_level @parallel_level end |
#seed ⇒ ProgramID (readonly)
Returns a seed object that is passed to new slaves to represent the currently known state of file, to avoid unnecessary respawning.
12 13 14 |
# File 'lib/autorespawn/manager.rb', line 12 def seed @seed end |
#self_slave ⇒ Self (readonly)
Returns an object that has the same API than [Slave] to represent the manager’s process itself. It is always included in #workers and #active_slaves.
18 19 20 |
# File 'lib/autorespawn/manager.rb', line 18 def self_slave @self_slave end |
#workers ⇒ Array<Slave> (readonly)
Returns declared worker processes, as a hash from the PID to a Slave object.
23 24 25 |
# File 'lib/autorespawn/manager.rb', line 23 def workers @workers end |
Instance Method Details
#active?(slave) ⇒ Boolean
Tests whether this slave is currently active on self
94 95 96 |
# File 'lib/autorespawn/manager.rb', line 94 def active?(slave) active_slaves[slave.pid] == slave end |
#add_slave(*cmdline, name: nil, **spawn_options) ⇒ Object
Spawns a worker, i.e. a program that will perform the intended work and report the program state
103 104 105 106 107 |
# File 'lib/autorespawn/manager.rb', line 103 def add_slave(*cmdline, name: nil, **) slave = Slave.new(*cmdline, name: name, seed: seed, **) register_slave(slave) slave end |
#clear ⇒ Object
Kill and remove all workers from this manager
171 172 173 174 175 176 177 178 |
# File 'lib/autorespawn/manager.rb', line 171 def clear kill workers.dup.each do |w| if w != self_slave remove_slave(w) end end end |
#collect_finished_slaves(wait: false) ⇒ Array<Slave>
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.
Collect information about the finished slaves
134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 |
# File 'lib/autorespawn/manager.rb', line 134 def collect_finished_slaves(wait: false) finished_slaves = Array.new = if wait then [] else [Process::WNOHANG] end while finished_child = Process.waitpid2(-1, *) pid, status = *finished_child if slave = active_slaves.delete(pid) finished_slaves << slave slave.finished(status) slave.subcommands.each do |name, cmdline, | add_slave(*cmdline, name: name, **) end seed.merge!(slave.program_id) run_hook :on_slave_finished, slave end end finished_slaves rescue Errno::ECHILD Array.new end |
#include?(slave) ⇒ Boolean
Tests whether this slave is registered as a worker on self
89 90 91 |
# File 'lib/autorespawn/manager.rb', line 89 def include?(slave) workers.include?(slave) end |
#kill ⇒ Object
Kill all active slaves
161 162 163 164 165 166 |
# File 'lib/autorespawn/manager.rb', line 161 def kill active_slaves.each { |s| s.kill(join: false) } while active_slaves != [self_slave] collect_finished_slaves(wait: true) end end |
#on_slave_finished {|the| ... } ⇒ Object
Hook called when a slave finishes
59 |
# File 'lib/autorespawn/manager.rb', line 59 define_hooks :on_slave_finished |
#on_slave_new(&block) {|the| ... } ⇒ Object
Register a callback for when a new slave is added by #add_slave
33 34 35 36 37 38 |
# File 'lib/autorespawn/manager.rb', line 33 def on_slave_new(&block) __on_slave_new(&block) workers.each do |w| block.call(w) end end |
#on_slave_removed {|the| ... } ⇒ Object
Hook called when a slave has been removed from this manager
66 |
# File 'lib/autorespawn/manager.rb', line 66 define_hooks :on_slave_removed |
#on_slave_start(&block) {|the| ... } ⇒ Object
Register a callback that should be called when a new slave has been spawned by #poll
46 47 48 49 50 51 |
# File 'lib/autorespawn/manager.rb', line 46 def on_slave_start(&block) __on_slave_start(&block) active_slaves.each_value do |w| block.call(w) end end |
#poll ⇒ Object
Wait for children to terminate and spawns them when needed
194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 |
# File 'lib/autorespawn/manager.rb', line 194 def poll finished_slaves = collect_finished_slaves new_slaves = Array.new while active_slaves.size < parallel_level if slave_i = workers.index { |s| s.needs_spawn? } slave = workers.delete_at(slave_i) @workers = workers[slave_i..-1] + workers[0, slave_i] + [slave] slave.spawn run_hook :__on_slave_start, slave new_slaves << slave active_slaves[slave.pid] = slave else break end end return new_slaves, finished_slaves end |
#register_seed_files(files, search_patch = seed.ruby_load_path, ignore_not_found: true) ⇒ Object
Add files to #seed
(see ProgramID#register_files)
84 85 86 |
# File 'lib/autorespawn/manager.rb', line 84 def register_seed_files(files, search_patch = seed.ruby_load_path, ignore_not_found: true) seed.register_files(files, search_path, ignore_not_found) end |
#register_slave(slave) ⇒ 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.
Registers a slave
123 124 125 126 127 |
# File 'lib/autorespawn/manager.rb', line 123 def register_slave(slave) workers << slave run_hook :__on_slave_new, slave slave end |
#remove_slave(slave) ⇒ Object
Remove a worker from this manager
112 113 114 115 116 117 118 |
# File 'lib/autorespawn/manager.rb', line 112 def remove_slave(slave) if active?(slave) raise ArgumentError, "#{slave} is still running" end workers.delete(slave) run_hook :on_slave_removed, slave end |
#run ⇒ Object
180 181 182 183 184 185 186 187 188 189 190 191 |
# File 'lib/autorespawn/manager.rb', line 180 def run while true poll sleep 1 end rescue Interrupt ensure active_slaves.values.each do |slave| slave.kill end end |