# encoding: UTF-8 require 'process_manager/child' require 'thread' module InstanceAgent module Runner class Child < ProcessManager::Daemon::Child attr_accessor :runner @prepare_run_done = false def load_plugins(plugins) ProcessManager::Log.debug("Registering Plugins: #{plugins.inspect}.") plugins.each do |plugin| plugin_dir = File.expand_path("../plugins/#{plugin}/register_plugin", File.dirname(__FILE__)) ProcessManager::Log.debug("Loading plugin #{plugin} from #{plugin_dir}") begin require plugin_dir rescue LoadError => e ProcessManager::Log.error("Plugin #{plugin} could not be loaded: #{e.message}.") raise end end registered_plugins = InstanceAgent::Agent::Base.plugins ProcessManager::Log.debug("Registered Plugins: #{registered_plugins.inspect}.") Hash[registered_plugins.map.with_index { |value, index| [index, value] }] end def prepare_run @plugins ||= load_plugins(ProcessManager::Config.config[:plugins] || ["codedeploy"]) validate_index with_error_handling do @runner = @plugins[index].runner ProcessManager.set_program_name(description) @runner.recover_from_crash?() end @prepare_run_done = true end def run with_error_handling do runner.run end end # Stops the master after recieving the kill signal # is overriden from ProcessManager::Daemon::Child def stop if @prepare_run_done @runner.graceful_shutdown end ProcessManager::Log.info('agent exiting now') super end # Catches the trap signals and does a default or custom action # is overriden from ProcessManager::Daemon::Child def trap_signals [:INT, :QUIT, :TERM].each do |sig| trap(sig) do ProcessManager::Log.info "#{description}: Received #{sig} - setting internal shutting down flag and possibly finishing last run" stop_thread = Thread.new {stop} stop_thread.join end end # make sure we do not handle children like the master process trap(:CHLD, 'DEFAULT') end def description if runner "#{runner.description} of master #{master_pid.inspect}" else 'booting child' end end def validate_index raise ArgumentError, "Invalid index #{index.inspect}" unless @plugins.keys.include?(index) end def with_error_handling yield rescue SocketError => e ProcessManager::Log.info "#{description}: failed to run as the connection failed! #{e.class} - #{e.message} - #{e.backtrace.join("\n")}" sleep ProcessManager::Config.config[:wait_after_connection_problem] exit 1 rescue Exception => e if (e.message.to_s.match(/throttle/i) || e.message.to_s.match(/rateexceeded/i) rescue false) ProcessManager::Log.error "#{description}: ran into throttling - waiting for #{ProcessManager::Config.config[:wait_after_throttle_error]}s until retrying" sleep ProcessManager::Config.config[:wait_after_throttle_error] else ProcessManager::Log.error "#{description}: error during start or run: #{e.class} - #{e.message} - #{e.backtrace.join("\n")}" end exit 1 end end end end