module Resque::UniqueByArity::Modulizer
Public Class Methods
to_mod(configuration)
click to toggle source
# File lib/resque/unique_by_arity/modulizer.rb, line 4 def self.to_mod(configuration) Module.new do if configuration.unique_in_queue || configuration.unique_at_runtime || configuration.unique_across_queues # @return [Array<String, arguments>] the key base hash used to enforce uniqueness, and the arguments from the payload used to calculate it define_method(:redis_unique_hash) do |payload| payload = Resque.decode(Resque.encode(payload)) Resque::UniqueByArity.debug("payload is #{payload.inspect}") job = payload['class'] # It seems possible that some jobs may not have an "args" key in the payload. args = payload['args'] || [] args.map! do |arg| arg.is_a?(Hash) ? arg.sort : arg end # what is the configured arity for uniqueness? uniqueness_args = if configuration.arity_for_uniqueness.zero? [] else # minus one because zero indexed, so # when arity_for_uniqueness is 2 we use args # at indexes 0 and 1. args[0..(configuration.arity_for_uniqueness - 1)] end args = { class: job, args: uniqueness_args } return [Digest::MD5.hexdigest(Resque.encode(args)), uniqueness_args] end end if configuration.unique_in_queue || configuration.unique_across_queues ### Gem: resque-unique_in_queue ### Plugin Name: Resque::Plugins::UniqueJob ### Provides: Queue-time uniqueness for a single queue, or across queues # # Returns a string, used by Resque::Plugins::UniqueJob, that will be used as the prefix to the redis key define_method(:unique_in_queue_redis_key_prefix) do "unique_job:#{self}" end # # Returns a string, used by Resque::Plugins::UniqueJob, that will be used as the redis key # The example in the readme is bad. The args passed to this method are like: # [{:class=>"MakeCompanyReport", :args=>[1]}] # Payload is what Resque stored for this job along with the job's class name: # a hash containing :class and :args # @return [String] the key used to enforce uniqueness (at queue-time) define_method(:unique_in_queue_redis_key) do |queue, payload| unique_hash, args_for_uniqueness = redis_unique_hash(payload) key = "#{unique_in_queue_key_namespace(queue)}:#{unique_in_queue_redis_key_prefix}:#{unique_hash}" Resque::UniqueByArity.debug("#{self}.unique_in_queue_redis_key for #{args_for_uniqueness} is: #{ColorizedString[key].green}") key end # # @return [Fixnum] number of keys that were deleted define_method(:purge_unique_queued_redis_keys) do # unique_in_queue_key_namespace may or may not ignore the queue passed in, depending on config. key_match = "#{unique_in_queue_key_namespace(instance_variable_get(:@queue))}:#{unique_in_queue_redis_key_prefix}:*" keys = Resque.redis.keys(key_match) Resque::UniqueByArity.log("#{Resque::UniqueByArity::PLUGIN_TAG}#{Resque::UniqueInQueue::PLUGIN_TAG} #{ColorizedString['Purging'].red} #{keys.length} keys from #{ColorizedString[key_match].red}") Resque.redis.del keys unless keys.empty? end if configuration.unique_in_queue # @return [String] the Redis namespace of the key used to enforce uniqueness (at queue-time) define_method(:unique_in_queue_key_namespace) do |queue = nil| "#{unique_in_queue_key_base}:queue:#{queue}:job" end elsif configuration.unique_across_queues # @return [String] the Redis namespace of the key used to enforce uniqueness (at queue-time) define_method(:unique_in_queue_key_namespace) do |_queue = nil| "#{unique_in_queue_key_base}:across_queues:job" end end end ### Gem: resque-unique_at_runtime ### Plugin Name: Resque::Plugins::UniqueAtRuntime ### Provides: Runtime uniqueness across queues if configuration.unique_at_runtime # @return [String] the Redis namespace of the key used to enforce uniqueness (at runtime) define_method(:runtime_key_namespace) do "#{unique_at_runtime_key_base}:#{self}" end # Returns a string, used by Resque::Plugins::UniqueAtRuntime, that will be used as the redis key # The versions of redis_key from resque-solo and resque-lonely_job are incompatible. # So I forked and namespaced the methods according to the gem handling the key. # Now I can override it, and fix the params to be compatible. # Does not need any customization for arity, because ultimately it # still funnels down to redis_key, and we handle the arity option there # @return [String] the key used to enforce loneliness (uniqueness at runtime) define_method(:unique_at_runtime_redis_key) do |*args| unique_hash, args_for_uniqueness = redis_unique_hash('class' => to_s, 'args' => args) key = "#{runtime_key_namespace}:#{unique_hash}" Resque::UniqueByArity.debug("#{Resque::UniqueAtRuntime::PLUGIN_TAG} #{self}.unique_at_runtime_redis_key for #{args_for_uniqueness} is: #{ColorizedString[key].yellow}") key end # @return [Fixnum] number of keys that were deleted define_method(:purge_unique_at_runtime_redis_keys) do key_match = "#{runtime_key_namespace}:*" keys = Resque.redis.keys(key_match) Resque::UniqueByArity.log("#{Resque::UniqueByArity::PLUGIN_TAG}#{Resque::UniqueAtRuntime::PLUGIN_TAG} #{ColorizedString['Purging'].red} #{keys.length} keys from #{ColorizedString[key_match].red}") Resque.redis.del keys unless keys.empty? end end end end