lib/bluepill/process.rb in bluepill-0.0.51 vs lib/bluepill/process.rb in bluepill-0.0.52

- old
+ new

@@ -33,11 +33,15 @@ :monitor_children, :child_process_factory, :pid_command, - :auto_start + :auto_start, + + :supplementary_groups, + + :stop_signals ] attr_accessor :name, :watches, :triggers, :logger, :skip_ticks_until, :process_running attr_accessor *CONFIGURABLE_ATTRIBUTES attr_reader :children, :statistics @@ -85,10 +89,11 @@ event :restart do transition [:up, :down] => :restarting end before_transition any => any, :do => :notify_triggers + before_transition :stopping => any, :do => :clean_threads after_transition any => :starting, :do => :start_process after_transition any => :stopping, :do => :stop_process after_transition any => :restarting, :do => :restart_process @@ -99,10 +104,11 @@ @name = process_name @event_mutex = Monitor.new @watches = [] @triggers = [] @children = [] + @threads = [] @statistics = ProcessStatistics.new @actual_pid = options[:actual_pid] self.logger = options[:logger] checks.each do |name, opts| @@ -132,10 +138,13 @@ self.skip_ticks_until = nil # clear the memoization per tick @process_running = nil + # Deal with thread cleanup here since the stopping state isn't used + clean_threads if self.unmonitored? + # run state machine transitions super if self.up? self.run_watches @@ -286,10 +295,34 @@ logger.warning "Stop command execution returned non-zero exit code:" logger.warning result.inspect end end + elsif stop_signals + # issue stop signals with configurable delay between each + logger.warning "Sending stop signals to #{actual_pid}" + @threads << Thread.new(self, stop_signals.clone) do |process, stop_signals| + signal = stop_signals.shift + logger.info "Sending signal #{signal} to #{process.actual_pid}" + process.signal_process(signal.upcase) # send first signal + + until stop_signals.empty? + # we already checked to make sure stop_signals had an odd number of items + delay = stop_signals.shift + signal = stop_signals.shift + + logger.debug "Sleeping for #{delay} seconds" + sleep delay + #break unless signal_process(0) #break unless the process can be reached + unless process.signal_process(0) + logger.debug "Process has terminated." + break + end + logger.info "Sending signal #{signal} to #{process.actual_pid}" + process.signal_process(signal.upcase) + end + end else logger.warning "Executing default stop command. Sending TERM signal to #{actual_pid}" signal_process("TERM") end self.unlink_pid # TODO: we only write the pid file if we daemonize, should we only unlink it if we daemonize? @@ -318,10 +351,15 @@ self.stop_process # the tick will bring it back. end end + def clean_threads + @threads.each { |t| t.kill } + @threads.clear + end + def daemonize? !!self.daemonize end def monitor_children? @@ -420,10 +458,11 @@ :environment => self.environment, :pid_file => self.pid_file, :logger => self.logger, :stdin => self.stdin, :stdout => self.stdout, - :stderr => self.stderr + :stderr => self.stderr, + :supplementary_groups => self.supplementary_groups } end def with_timeout(secs, &blk) Timeout.timeout(secs.to_f, &blk)