# encoding: utf-8 module HireFire module Environment autoload :Base, 'hirefire/environment/base' autoload :Heroku, 'hirefire/environment/heroku' autoload :Local, 'hirefire/environment/local' autoload :Noop, 'hirefire/environment/noop' ## # This module gets included in either: # - Delayed::Backend::ActiveRecord::Job # - Delayed::Backend::Mongoid::Job # - Resque::Job # # One of these classes will then be provided with an instance of one of the following: # - HireFire::Environment::Heroku # - HireFire::Environment::Local # - HireFire::Environment::Noop # # This instance is stored in the Class.environment class method # # The Delayed Job classes receive 3 hooks: # - hirefire_hire ( invoked when a job gets queued ) # - environment.fire ( invoked when a queued job gets destroyed ) # - environment.fire ( invoked when a queued job gets updated unless the job didn't fail ) # # The Resque classes get their hooks injected from the HireFire::Initializer#initialize! method # # @param (Class) base This is the class in which this module will be included def self.included(base) base.send :extend, HireFire::Environment::ClassMethods ## # Only implement these hooks for Delayed::Job backends if base.name =~ /Delayed::Backend::(ActiveRecord|Mongoid)::Job/ base.send :extend, HireFire::Environment::DelayedJob::ClassMethods base.class_eval do after_create 'self.class.hirefire_hire' after_destroy 'self.class.environment.fire' after_update 'self.class.environment.fire', :unless => Proc.new { |job| job.failed_at.nil? } end end Logger.message("#{ base.name } detected!") end ## # Class methods that will be added to the # Delayed::Job and Resque::Job classes module ClassMethods ## # Returns the environment class method (containing an instance of the proper environment class) # for either Delayed::Job or Resque::Job # # If HireFire.configuration.environment is nil (the default) then it'll # auto-detect which environment to run in (either Heroku or Noop) # # If HireFire.configuration.environment isn't nil (explicitly set) then # it'll run in the specified environment (Heroku, Local or Noop) # # @return [HireFire::Environment::Heroku, HireFire::Environment::Local, HireFire::Environment::Noop] def environment @environment ||= HireFire::Environment.const_get( if environment = HireFire.configuration.environment environment.to_s.camelize else ENV.include?('HEROKU_UPID') ? 'Heroku' : 'Noop' end ).new end end ## # Delayed Job specific module module DelayedJob module ClassMethods ## # This method is an attempt to improve web-request throughput. # # A class method for Delayed::Job which first checks if any worker is currently # running by checking to see if there are any jobs locked by a worker. If there aren't # any jobs locked by a worker there is a high chance that there aren't any workers running. # If this is the case, then we sure also invoke the 'self.class.environment.hire' method # # Another check is to see if there is only 1 job (which is the one that # was just added before this callback invoked). If this is the case # then it's very likely there aren't any workers running and we should # invoke the 'self.class.environment.hire' method to make sure this is the case. # # @return [nil] def hirefire_hire delayed_job = ::Delayed::Job.new if delayed_job.working == 0 \ or delayed_job.jobs == 1 environment.hire end end end end end end