class Skiplock::Manager
Public Class Methods
new()
click to toggle source
# File lib/skiplock/manager.rb, line 3 def initialize @config = Skiplock::DEFAULT_CONFIG.dup @config.merge!(YAML.load_file('config/skiplock.yml')) rescue nil @config.symbolize_keys! Rails.application.eager_load! if Rails.env.development? if @config[:extensions] == true Module.__send__(:include, Skiplock::Extension) elsif @config[:extensions].is_a?(Array) @config[:extensions].each { |n| n.constantize.__send__(:extend, Skiplock::Extension) if n.safe_constantize } end ActiveJob::Base.__send__(:include, Skiplock::Patch) (caller.any?{ |l| l =~ %r{/rack/} } && @config[:workers] == 0) ? async : Cron.setup end
Public Instance Methods
async()
click to toggle source
# File lib/skiplock/manager.rb, line 17 def async setup_logger configure Worker.cleanup(@hostname) @worker = Worker.generate(capacity: @config[:max_threads], hostname: @hostname) Cron.setup if @worker.master @worker.start(**@config) at_exit { @worker.shutdown } rescue Exception => ex @logger.error(ex.to_s) @logger.error(ex.backtrace.join("\n")) end
standalone(**options)
click to toggle source
# File lib/skiplock/manager.rb, line 30 def standalone(**options) @config.merge!(options) @config[:standalone] = true @config[:workers] = 1 if @config[:workers] <= 0 setup_logger configure banner @parent_id = Process.pid @shutdown = false Signal.trap('INT') { @shutdown = true } Signal.trap('TERM') { @shutdown = true } Signal.trap('HUP') { setup_logger } Worker.cleanup(@hostname) @worker = Worker.generate(capacity: @config[:max_threads], hostname: @hostname) ActiveRecord::Base.connection.disconnect! if @config[:workers] > 1 (@config[:workers] - 1).times do |n| fork do sleep(0.25*n + 1) ActiveRecord::Base.establish_connection worker = Worker.generate(capacity: @config[:max_threads], hostname: @hostname, master: false) worker.start(worker_num: n + 1, **@config) loop do sleep 0.5 break if @shutdown || Process.ppid != @parent_id end worker.shutdown end end ActiveRecord::Base.establish_connection if @config[:workers] > 1 @worker.start(**@config) loop do sleep 0.5 break if @shutdown end @logger.info "[Skiplock] Terminating signal... Waiting for jobs to finish (up to #{@config[:graceful_shutdown]} seconds)..." if @config[:graceful_shutdown] Process.waitall @worker.shutdown rescue Exception => ex @logger.error(ex.to_s) @logger.error(ex.backtrace.join("\n")) end
Private Instance Methods
configure()
click to toggle source
# File lib/skiplock/manager.rb, line 96 def configure @hostname = "#{`hostname -f`.strip}|#{Socket.ip_address_list.reject(&:ipv4_loopback?).reject(&:ipv6?).map(&:ip_address).join('|')}" @config.transform_values! {|v| v.is_a?(String) ? v.downcase : v} @config[:graceful_shutdown] = 300 if @config[:graceful_shutdown] > 300 @config[:graceful_shutdown] = nil if @config[:graceful_shutdown] < 0 @config[:max_retries] = 20 if @config[:max_retries] > 20 @config[:max_retries] = 0 if @config[:max_retries] < 0 @config[:max_threads] = 1 if @config[:max_threads] < 1 @config[:max_threads] = 20 if @config[:max_threads] > 20 @config[:min_threads] = 0 if @config[:min_threads] < 0 @config[:workers] = 0 if @config[:workers] < 0 @config[:queues].values.each { |v| raise 'Queue value must be an integer' unless v.is_a?(Integer) } if @config[:queues].is_a?(Hash) if @config[:notification] == 'auto' if defined?(Airbrake) @config[:notification] = 'airbrake' elsif defined?(Bugsnag) @config[:notification] = 'bugsnag' elsif defined?(ExceptionNotifier) @config[:notification] = 'exception_notification' else raise "Unable to detect any known exception notification library. Please define custom 'on_error' event callbacks and change to 'custom' notification in 'config/skiplock.yml'" end end case @config[:notification] when 'airbrake' raise 'airbrake gem not found' unless defined?(Airbrake) Skiplock.on_error do |ex| Airbrake.notify_sync(ex) end when 'bugsnag' raise 'bugsnag gem not found' unless defined?(Bugsnag) Skiplock.on_error do |ex| Bugsnag.notify(ex) end when 'exception_notification' raise 'exception_notification gem not found' unless defined?(ExceptionNotifier) Skiplock.on_error do |ex| ExceptionNotifier.notify_exception(ex) end else @config[:notification] = 'custom' end Skiplock.namespace = @config[:namespace] Skiplock.on_errors.freeze end
setup_logger()
click to toggle source
# File lib/skiplock/manager.rb, line 142 def setup_logger @config[:loglevel] = 'info' unless ['debug','info','warn','error','fatal','unknown'].include?(@config[:loglevel].to_s) @logger = ActiveSupport::Logger.new(STDOUT) @logger.level = @config[:loglevel].to_sym Skiplock.logger = @logger if @config[:logfile].to_s.length > 0 @logger.extend(ActiveSupport::Logger.broadcast(::Logger.new(File.join(Rails.root, 'log', @config[:logfile].to_s), 'daily'))) ActiveJob::Base.logger = nil end if @config[:standalone] Rails.logger.reopen('/dev/null') rescue Rails.logger.reopen('NUL') # supports Windows NUL device Rails.logger.level = @logger.level Rails.logger.extend(ActiveSupport::Logger.broadcast(@logger)) end rescue Exception => ex @logger.error "Exception with logger: #{ex.to_s}" @logger.error ex.backtrace.join("\n") Skiplock.on_errors.each { |p| p.call(ex) } end