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
The number of processes allowed to work in parallel.
-
#queued_slaves ⇒ Array<Slave>
readonly
List of slaves explicitely queued with #queue.
-
#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 ⇒ Array<Slave>
private
Collect information about the finished slaves.
-
#has_active_slaves? ⇒ Boolean
Tests whether this manager has some slaves that are active.
-
#has_slaves? ⇒ Boolean
Check whether this manager has 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(autospawn: true) ⇒ Object
Wait for children to terminate and spawns them when needed.
- #process_finished_slave(pid, status) ⇒ Object
-
#queue(slave) ⇒ Object
Queue a slave for execution.
-
#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
-
#slave_count ⇒ Object
The number of slaves registered.
Methods included from Hooks
Constructor Details
#initialize(name: nil, parallel_level: 1) ⇒ Manager
Returns a new instance of Manager.
72 73 74 75 76 77 78 79 80 81 82 |
# File 'lib/autorespawn/manager.rb', line 72 def initialize(name: nil, parallel_level: 1) @parallel_level = parallel_level @workers = Array.new @name = name @seed = ProgramID.for_self @self_slave = Self.new(name: name) @workers << self_slave @queued_slaves = Array.new @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
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 |
#queued_slaves ⇒ Array<Slave> (readonly)
Returns list of slaves explicitely queued with #queue.
27 28 29 |
# File 'lib/autorespawn/manager.rb', line 27 def queued_slaves @queued_slaves 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
113 114 115 |
# File 'lib/autorespawn/manager.rb', line 113 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
122 123 124 125 126 |
# File 'lib/autorespawn/manager.rb', line 122 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
195 196 197 198 199 200 201 202 |
# File 'lib/autorespawn/manager.rb', line 195 def clear kill workers.dup.each do |w| if w != self_slave remove_slave(w) end end end |
#collect_finished_slaves ⇒ 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
158 159 160 161 162 163 164 165 166 |
# File 'lib/autorespawn/manager.rb', line 158 def collect_finished_slaves finished_slaves = Array.new while finished_child = Process.waitpid2(-1, Process::WNOHANG) finished_slaves << process_finished_slave(*finished_child) end finished_slaves rescue Errno::ECHILD finished_slaves end |
#has_active_slaves? ⇒ Boolean
Tests whether this manager has some slaves that are active
108 109 110 |
# File 'lib/autorespawn/manager.rb', line 108 def has_active_slaves? active_slaves.size != 1 end |
#has_slaves? ⇒ Boolean
Check whether this manager has slaves
92 93 94 95 |
# File 'lib/autorespawn/manager.rb', line 92 def has_slaves? # There's always a worker for self workers.size != 1 end |
#include?(slave) ⇒ Boolean
Tests whether this slave is registered as a worker on self
103 104 105 |
# File 'lib/autorespawn/manager.rb', line 103 def include?(slave) workers.include?(slave) end |
#kill ⇒ Object
Kill all active slaves
183 184 185 186 187 188 189 190 |
# File 'lib/autorespawn/manager.rb', line 183 def kill active_slaves.each_value { |s| s.kill(join: false) } while has_active_slaves? finished_child = Process.waitpid2(-1) process_finished_slave(*finished_child) end rescue Errno::ECHILD end |
#on_slave_finished {|the| ... } ⇒ Object
Hook called when a slave finishes
61 |
# File 'lib/autorespawn/manager.rb', line 61 define_hooks :on_slave_finished |
#on_slave_new(&block) {|the| ... } ⇒ Object
Register a callback for when a new slave is added by #add_slave
35 36 37 38 39 40 |
# File 'lib/autorespawn/manager.rb', line 35 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
68 |
# File 'lib/autorespawn/manager.rb', line 68 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
48 49 50 51 52 53 |
# File 'lib/autorespawn/manager.rb', line 48 def on_slave_start(&block) __on_slave_start(&block) active_slaves.each_value do |w| block.call(w) end end |
#poll(autospawn: true) ⇒ Object
Wait for children to terminate and spawns them when needed
218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 |
# File 'lib/autorespawn/manager.rb', line 218 def poll(autospawn: true) finished_slaves = collect_finished_slaves new_slaves = Array.new while active_slaves.size < parallel_level + 1 if slave = queued_slaves.find { |s| !s.running? } queued_slaves.delete(slave) elsif autospawn && (slave_i = workers.index { |s| s.needed? }) slave = workers.delete_at(slave_i) @workers = workers[slave_i..-1] + workers[0, slave_i] + [slave] end if 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 |
#process_finished_slave(pid, status) ⇒ Object
168 169 170 171 172 173 174 175 176 177 178 |
# File 'lib/autorespawn/manager.rb', line 168 def process_finished_slave(pid, status) return if !(slave = active_slaves.delete(pid)) 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 slave end |
#queue(slave) ⇒ Object
Queue a slave for execution
149 150 151 |
# File 'lib/autorespawn/manager.rb', line 149 def queue(slave) queued_slaves << slave end |
#register_seed_files(files, search_patch = seed.ruby_load_path, ignore_not_found: true) ⇒ Object
Add files to #seed
(see ProgramID#register_files)
87 88 89 |
# File 'lib/autorespawn/manager.rb', line 87 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
142 143 144 145 146 |
# File 'lib/autorespawn/manager.rb', line 142 def register_slave(slave) workers << slave run_hook :__on_slave_new, slave slave end |
#remove_slave(slave) ⇒ Object
Remove a worker from this manager
131 132 133 134 135 136 137 |
# File 'lib/autorespawn/manager.rb', line 131 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
204 205 206 207 208 209 210 211 212 213 214 215 |
# File 'lib/autorespawn/manager.rb', line 204 def run while true poll sleep 1 end rescue Interrupt ensure active_slaves.values.each do |slave| slave.kill end end |
#slave_count ⇒ Object
The number of slaves registered
98 99 100 |
# File 'lib/autorespawn/manager.rb', line 98 def slave_count workers.size - 1 end |