class Resque::Plugins::DisableJob::Job

The Job class contains the logic that determines if the current job is disabled, and methods to disable and enable a specific job.

Public Class Methods

disable_job(name, specific_args: {}, timeout: DEFAULT_TIMEOUT) click to toggle source

To disable a job we need to add it in 3 data structures:

  • we need to add the job name to the main set so we know what jobs have rules

  • we add the arguments to the job's rule hash

  • we create a counter for the individual rule that will keep track of how many times it was matched

# File lib/resque/plugins/disable_job/job.rb, line 55
def self.disable_job(name, specific_args: {}, timeout: DEFAULT_TIMEOUT)
  rule = Rule.new(name, specific_args)
  Resque.redis.multi do
    Resque.redis.sadd rule.main_set, rule.job_name
    Resque.redis.hset(rule.all_rules_key, rule.digest, rule.serialized_arguments)
    Resque.redis.set(rule.rule_key, 0)
    Resque.redis.expire(rule.rule_key, timeout)
  end
end
disabled?(job_name, job_args) click to toggle source

disabled? checks if the job and it's arguments is disabled

# File lib/resque/plugins/disable_job/job.rb, line 12
def self.disabled?(job_name, job_args)
  # We get all the rules for the current job
  rules = get_all_rules(job_name)
  # We limit this to 10 rules for performance reasons. Each check delays the job from being performed
  matched_rule = match_rules(job_name, job_args, rules)

  if !matched_rule.nil?
    # if we found a matched rule, we record this and return true
    record_matched_rule(job_name, job_args, matched_rule)
    true
  else
    false
  end
end
disabled_jobs() click to toggle source
# File lib/resque/plugins/disable_job/job.rb, line 78
def self.disabled_jobs
  Resque.redis.smembers(Rule::JOBS_SET)
end
enable_all(job_name) click to toggle source
# File lib/resque/plugins/disable_job/job.rb, line 70
def self.enable_all(job_name)
  get_all_rules(job_name).map { |r| remove_specific_rule(r) }
end
enable_all!() click to toggle source
# File lib/resque/plugins/disable_job/job.rb, line 74
def self.enable_all!
  disabled_jobs.map { |job_name| enable_all(job_name) }
end
enable_job(name, specific_args: {}) click to toggle source

To enable a job, we just need to remove it

# File lib/resque/plugins/disable_job/job.rb, line 66
def self.enable_job(name, specific_args: {})
  remove_specific_rule(Rule.new(name, specific_args))
end
expired?(rule) click to toggle source

The rule is expired if the TTL of the rule key is -1.

# File lib/resque/plugins/disable_job/job.rb, line 47
def self.expired?(rule)
  Resque.redis.ttl(rule.rule_key) < 0 # .negative? only works in Ruby 2.3 and above
end
match_rules(job_name, job_args, rules) click to toggle source
# File lib/resque/plugins/disable_job/job.rb, line 27
def self.match_rules(job_name, job_args, rules)
  rules.take(MAX_JOB_RULES).detect do |specific_rule|
    begin
      # if the rule is not expired
      if !expired?(specific_rule)
        # if the arguments received and the ones from the rule match, that means that we need to disable the current job
        specific_rule.match?(job_args)
      else
        # we remove the rule if it's expired
        remove_specific_rule(specific_rule)
        false
      end
    rescue StandardError => e
      Resque.logger.error "Failed to parse AllowDisableJob rules for #{job_name}: #{specific_rule.serialized_arguments}. Error: #{e.message}"
      false
    end
  end
end
remove_specific_rule(rule) click to toggle source

To remove a job we need to delete its counter, the entry from the rules hash and if the job has no more rules, we can remove the job's entry in the main set

# File lib/resque/plugins/disable_job/job.rb, line 84
def self.remove_specific_rule(rule)
  Resque.redis.del(rule.rule_key)
  Resque.redis.hdel(rule.all_rules_key, rule.digest)
  if Resque.redis.hlen(rule.all_rules_key).zero?
    Resque.redis.srem(rule.main_set, rule.job_name)
  end
end

Private Class Methods

get_all_rules(job_name) click to toggle source
# File lib/resque/plugins/disable_job/job.rb, line 100
def self.get_all_rules(job_name)
  Resque.redis.hgetall(Rule.new(job_name).all_rules_key).map do |digest, set_args|
    get_specific_rule(job_name, set_args, digest)
  end
end
get_specific_rule(job_name, set_args, digest) click to toggle source

Support functions for disabled?

# File lib/resque/plugins/disable_job/job.rb, line 94
def self.get_specific_rule(job_name, set_args, digest)
  rule = Rule.new(job_name, set_args)
  Resque.logger.error 'The DIGEST does not match' if rule.digest != digest
  rule
end
record_matched_rule(job_name, job_args, rule) click to toggle source
# File lib/resque/plugins/disable_job/job.rb, line 106
def self.record_matched_rule(job_name, job_args, rule)
  Resque.redis.incr rule.rule_key
  Resque.logger.info "Matched running job #{job_name}(#{job_args}) because it was disabled by #{rule}"
end