module Concurrency::ClassMethods

Public Instance Methods

concurrency_cache() click to toggle source
# File lib/rails_core_extensions/concurrency.rb, line 19
def concurrency_cache
  @concurrency_cache ||= ::Rails.cache
end
concurrency_cache=(cache) click to toggle source
# File lib/rails_core_extensions/concurrency.rb, line 24
def concurrency_cache=(cache)
  [:read,:write,:delete].each do |method|
    raise ConcurrencyCacheException, "#{cache} does not implement #{method}" unless cache.respond_to?(method)
  end
  @concurrency_cache = cache
end
concurrency_safe(*methods) click to toggle source
# File lib/rails_core_extensions/concurrency.rb, line 6
def concurrency_safe(*methods)
  options = methods.extract_options!
  methods.each do |method|
    add_concurrency_check(method, options)
  end
end
concurrency_safe_method_locked?(method) click to toggle source
# File lib/rails_core_extensions/concurrency.rb, line 14
def concurrency_safe_method_locked?(method)
  concurrency_cache.read(concurrency_safe_method_cache_name(method)) == 'locked'
end

Private Instance Methods

add_concurrency_check(method, options = {}) click to toggle source
# File lib/rails_core_extensions/concurrency.rb, line 34
    def add_concurrency_check(method, options = {})
      method_definition = <<-DEFINITION
        def #{method}_with_concurrency_lock(*args)
          if concurrency_safe_method_locked?(:#{method})
            raise ConcurrentCallException.new(self,:#{method}), "#{self.name}.#{method} is already running"
          end
          lock_concurrency_safe_method(:#{method})
          return_value = nil
          begin
            return_value = #{method}_without_concurrency_lock(*args)
          ensure
            unlock_concurrency_safe_method(:#{method})
          end
          return_value
        end
        alias_method :#{method}_without_concurrency_lock, :#{method}
        alias_method :#{method}, :#{method}_with_concurrency_lock
      DEFINITION
      
      if method_type(method, options[:type]) == 'class'
        method_definition = <<-DEFINITION
          class << self
            #{method_definition}
          end
        DEFINITION
      end
      
      module_eval method_definition
    end
class_method?(method) click to toggle source
# File lib/rails_core_extensions/concurrency.rb, line 95
def class_method?(method)
  self.respond_to?(method, true)
end
concurrency_safe_method_cache_name(method) click to toggle source
# File lib/rails_core_extensions/concurrency.rb, line 75
def concurrency_safe_method_cache_name(method)
  "#{self.name.underscore}_concurrency_safe_class_method_#{method}"
end
instance_method?(method) click to toggle source
# File lib/rails_core_extensions/concurrency.rb, line 100
def instance_method?(method)
  (self.instance_methods + self.private_instance_methods).map(&:to_s).include?(method.to_s)
end
lock_concurrency_safe_method(method) click to toggle source
# File lib/rails_core_extensions/concurrency.rb, line 65
def lock_concurrency_safe_method(method)
  concurrency_cache.write(concurrency_safe_method_cache_name(method), 'locked')
end
method_type(method, type = nil) click to toggle source
# File lib/rails_core_extensions/concurrency.rb, line 80
def method_type(method, type = nil)
  types = method_types(method, type)
  raise AmbiguousMethodException.new(self, method), "#{method} for #{self.name} is ambiguous. Please specify the type (instance/class) option" if types.count == 2
  raise NoMethodException.new(self, method), "#{method} is not not a valid method for #{self.name}." if types.blank?
  types.first
end
method_types(method, type = nil) click to toggle source
# File lib/rails_core_extensions/concurrency.rb, line 88
def method_types(method, type = nil)
  ['class', 'instance'].select do |mt|
    (type.blank? || type.to_s == mt) && self.send("#{mt}_method?", method)
  end
end
unlock_concurrency_safe_method(method) click to toggle source
# File lib/rails_core_extensions/concurrency.rb, line 70
def unlock_concurrency_safe_method(method)
  concurrency_cache.delete(concurrency_safe_method_cache_name(method))
end