Gurpartap/cognizant

View on GitHub
lib/cognizant/process/actions.rb

Summary

Maintainability
A
1 hr
Test Coverage
require "cognizant/process/actions/start"
require "cognizant/process/actions/stop"
require "cognizant/process/actions/restart"
require "cognizant/system"

module Cognizant
  class Process
    module Actions
      include Cognizant::Process::Actions::Start
      include Cognizant::Process::Actions::Stop
      include Cognizant::Process::Actions::Restart

      private

      def handle_action(result_handler, options)
        # TODO: Works well but can some refactoring make it more declarative?
        @action_thread = Thread.new do
          result = false
          queue, thread = execute_action(options)

          time_left = options[:timeout]
          while time_left >= 0 do
            # If there is something in the queue, we have the required result.
            unless queue.empty?
              result = queue.pop
              break
            end
            sleep 1
            time_left -= 1
          end

          # Kill the nested thread.
          thread.kill

          # Action callback.
          self.send(result_handler, result, time_left) if result_handler.present? and self.respond_to?(result_handler)
        end
      end

      def execute_action(options)
        before_command = options[:before]
        command        = options[:command]
        after_command  = options[:after]
        signals        = options[:signals]
        timeout        = options[:timeout]

        queue = Queue.new
        thread = Thread.new do
          # If before_command succeeds, we move to the next command.
          (before_command and not success = run(before_command).succeeded?) or
          # If the command is available and it succeeds, we stop here.
          (command and success = run(command, options) and success.succeeded?) or
          # As a last try, check for signals. If the action has set signals, then it can handle its result.
          (success = send_signals(signals: signals, timeout: timeout))

          run(after_command) if success and after_command
          queue.push(success)
          Thread.exit
        end
        return queue, thread
      end

      def send_signals(options = {})
        # Return if the process is already stopped.
        return true unless pid_running?
        Cognizant::System.send_signals(@process_pid, options)
        not pid_running?
      end
    end
  end
end