Class: Procodile::Supervisor
- Inherits:
-
Object
- Object
- Procodile::Supervisor
- Defined in:
- lib/procodile/supervisor.rb
Instance Attribute Summary collapse
-
#config ⇒ Object
readonly
Returns the value of attribute config.
-
#processes ⇒ Object
readonly
Returns the value of attribute processes.
-
#run_options ⇒ Object
readonly
Returns the value of attribute run_options.
-
#started_at ⇒ Object
readonly
Returns the value of attribute started_at.
-
#tag ⇒ Object
readonly
Returns the value of attribute tag.
-
#tcp_proxy ⇒ Object
readonly
Returns the value of attribute tcp_proxy.
Instance Method Summary collapse
- #add_instance(instance, io = nil) ⇒ Object
- #add_reader(instance, io) ⇒ Object
- #allow_respawning? ⇒ Boolean
- #check_concurrency(options = {}) ⇒ Object
-
#initialize(config, run_options = {}) ⇒ Supervisor
constructor
A new instance of Supervisor.
- #messages ⇒ Object
- #reload_config ⇒ Object
- #remove_instance(instance) ⇒ Object
- #restart(options = {}) ⇒ Object
- #start(&after_start) ⇒ Object
- #start_processes(types = nil, options = {}) ⇒ Object
- #stop(options = {}) ⇒ Object
- #stop_supervisor ⇒ Object
- #supervise ⇒ Object
- #supervise! ⇒ Object
- #to_hash ⇒ Object
Constructor Details
#initialize(config, run_options = {}) ⇒ Supervisor
Returns a new instance of Supervisor.
14 15 16 17 18 19 20 21 22 23 24 25 |
# File 'lib/procodile/supervisor.rb', line 14 def initialize(config, = {}) @config = config @run_options = @processes = {} @readers = {} @signal_handler = SignalHandler.new('TERM', 'USR1', 'USR2', 'INT', 'HUP') @signal_handler.register('TERM') { stop_supervisor } @signal_handler.register('INT') { stop(:stop_supervisor => true) } @signal_handler.register('USR1') { restart } @signal_handler.register('USR2') { } @signal_handler.register('HUP') { reload_config } end |
Instance Attribute Details
#config ⇒ Object (readonly)
Returns the value of attribute config.
7 8 9 |
# File 'lib/procodile/supervisor.rb', line 7 def config @config end |
#processes ⇒ Object (readonly)
Returns the value of attribute processes.
8 9 10 |
# File 'lib/procodile/supervisor.rb', line 8 def processes @processes end |
#run_options ⇒ Object (readonly)
Returns the value of attribute run_options.
12 13 14 |
# File 'lib/procodile/supervisor.rb', line 12 def @run_options end |
#started_at ⇒ Object (readonly)
Returns the value of attribute started_at.
9 10 11 |
# File 'lib/procodile/supervisor.rb', line 9 def started_at @started_at end |
#tag ⇒ Object (readonly)
Returns the value of attribute tag.
10 11 12 |
# File 'lib/procodile/supervisor.rb', line 10 def tag @tag end |
#tcp_proxy ⇒ Object (readonly)
Returns the value of attribute tcp_proxy.
11 12 13 |
# File 'lib/procodile/supervisor.rb', line 11 def tcp_proxy @tcp_proxy end |
Instance Method Details
#add_instance(instance, io = nil) ⇒ Object
200 201 202 203 204 205 206 |
# File 'lib/procodile/supervisor.rb', line 200 def add_instance(instance, io = nil) add_reader(instance, io) if io @processes[instance.process] ||= [] unless @processes[instance.process].include?(instance) @processes[instance.process] << instance end end |
#add_reader(instance, io) ⇒ Object
195 196 197 198 |
# File 'lib/procodile/supervisor.rb', line 195 def add_reader(instance, io) @readers[io] = instance @signal_handler.notice end |
#allow_respawning? ⇒ Boolean
27 28 29 |
# File 'lib/procodile/supervisor.rb', line 27 def allow_respawning? @run_options[:respawn] != false end |
#check_concurrency(options = {}) ⇒ Object
155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 |
# File 'lib/procodile/supervisor.rb', line 155 def check_concurrency( = {}) Procodile.log nil, "system", "Checking process concurrency" reload_config unless [:reload] == false result = check_instance_quantities if result[:started].empty? && result[:stopped].empty? Procodile.log nil, "system", "Process concurrency looks good" else unless result[:started].empty? Procodile.log nil, "system", "Concurrency check started #{result[:started].map(&:description).join(', ')}" end unless result[:stopped].empty? Procodile.log nil, "system", "Concurrency check stopped #{result[:stopped].map(&:description).join(', ')}" end end result end |
#messages ⇒ Object
180 181 182 183 184 185 186 187 188 189 190 191 192 193 |
# File 'lib/procodile/supervisor.rb', line 180 def = [] processes.each do |process, process_instances| unless process.correct_quantity?(process_instances.size) << {:type => :incorrect_quantity, :process => process.name, :current => process_instances.size, :desired => process.quantity} end for instance in process_instances if instance.should_be_running? && instance.status != 'Running' << {:type => :not_running, :instance => instance.description, :status => instance.status} end end end end |
#reload_config ⇒ Object
150 151 152 153 |
# File 'lib/procodile/supervisor.rb', line 150 def reload_config Procodile.log nil, "system", "Reloading configuration" @config.reload end |
#remove_instance(instance) ⇒ Object
208 209 210 211 212 213 |
# File 'lib/procodile/supervisor.rb', line 208 def remove_instance(instance) if @processes[instance.process] @processes[instance.process].delete(instance) @readers.delete(instance) end end |
#restart(options = {}) ⇒ Object
95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 |
# File 'lib/procodile/supervisor.rb', line 95 def restart( = {}) @tag = [:tag] reload_config Array.new.tap do |instances_restarted| if [:processes].nil? Procodile.log nil, "system", "Restarting all #{@config.app_name} processes" instances = @processes.values.flatten else instances = process_names_to_instances([:processes]) Procodile.log nil, "system", "Restarting #{instances.size} process(es)" end # Stop any processes that are no longer wanted at this point instances_restarted.push(*check_instance_quantities(:stopped, [:processes])[:stopped].map { |i| [i, nil]}) instances.each do |instance| next if instance.stopping? new_instance = instance.restart instances_restarted << [instance, new_instance] end # Start any processes that are needed at this point instances_restarted.push(*check_instance_quantities(:started, [:processes])[:started].map { |i| [nil, i]}) end end |
#start(&after_start) ⇒ Object
31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
# File 'lib/procodile/supervisor.rb', line 31 def start(&after_start) Procodile.log nil, "system", "Procodile supervisor started with PID #{::Process.pid}" Procodile.log nil, "system", "Application root is #{@config.root}" if @run_options[:respawn] == false Procodile.log nil, "system", "Automatic respawning is disabled" end ControlServer.start(self) if @run_options[:proxy] Procodile.log nil, "system", "Proxy is enabled" @tcp_proxy = TCPProxy.start(self) end watch_for_output @started_at = Time.now after_start.call(self) if block_given? supervise! rescue => e Procodile.log nil, "system", "Error: #{e.class} (#{e.})" e.backtrace.each { |bt| Procodile.log nil, "system", "=> #{bt})" } stop(:stop_supervisor => true) supervise! end |
#start_processes(types = nil, options = {}) ⇒ Object
57 58 59 60 61 62 63 64 65 66 67 68 |
# File 'lib/procodile/supervisor.rb', line 57 def start_processes(types = nil, = {}) @tag = [:tag] reload_config Array.new.tap do |instances_started| @config.processes.each do |name, process| next if types && !types.include?(name.to_s) # Not a process we want next if @processes[process] && !@processes[process].empty? # Process type already running instances = process.generate_instances(self).each(&:start) instances_started.push(*instances) end end end |
#stop(options = {}) ⇒ Object
70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 |
# File 'lib/procodile/supervisor.rb', line 70 def stop( = {}) if [:stop_supervisor] @run_options[:stop_when_none] = true end reload_config Array.new.tap do |instances_stopped| if [:processes].nil? Procodile.log nil, "system", "Stopping all #{@config.app_name} processes" @processes.each do |_, instances| instances.each do |instance| instance.stop instances_stopped << instance end end else instances = process_names_to_instances([:processes]) Procodile.log nil, "system", "Stopping #{instances.size} process(es)" instances.each do |instance| instance.stop instances_stopped << instance end end end end |
#stop_supervisor ⇒ Object
121 122 123 124 125 |
# File 'lib/procodile/supervisor.rb', line 121 def stop_supervisor Procodile.log nil, 'system', "Stopping Procodile supervisor" FileUtils.rm_f(File.join(@config.pid_root, 'procodile.pid')) ::Process.exit 0 end |
#supervise ⇒ Object
127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 |
# File 'lib/procodile/supervisor.rb', line 127 def supervise # Tell instances that have been stopped that they have been stopped remove_stopped_instances # Remove removed processes remove_removed_processes # Check all instances that we manage and let them do their things. @processes.each do |_, instances| instances.each do |instance| instance.check end end if @run_options[:stop_when_none] # If the processes go away, we can stop the supervisor now if @processes.all? { |_,instances| instances.reject(&:failed?).size == 0 } Procodile.log nil, "system", "All processes have stopped" stop_supervisor end end end |
#supervise! ⇒ Object
53 54 55 |
# File 'lib/procodile/supervisor.rb', line 53 def supervise! loop { supervise; sleep 3 } end |
#to_hash ⇒ Object
173 174 175 176 177 178 |
# File 'lib/procodile/supervisor.rb', line 173 def to_hash { :started_at => @started_at ? @started_at.to_i : nil, :pid => ::Process.pid } end |