module Logical 
  class CachedObject 

    def self.lock_key(key) 
      "lock:#{key}" 
    end 

    def self.locked?(key, timeout_seconds = 10) 
      start = CACHE[lock_key(key)] 
      start? Time.new - start < timeout_seconds : false 
    end 

    def self.with_lock(key, timeout_seconds 10, &block) 
      start = Time.new 
      acquired_lock = false 
      while (Time.new - start < timeout_seconds) && !acquired_lock 
        acquired_lock = !CACHE.add(lock_key(key), Time.new).index("NOT_STORED")
        sleep 0.1 if !acquired_lock 
      end 
      yield 
      CACHE.delete(lock_key(key)) 
    end 
  
    def self.get(*params) 
      key = cache_key(params) 
      sleep 0.1 while locked?(key) 
      CACHE[key] ||= self.uncached_class.get(params) 
    end 

    def self.rebuild(*params) 
      key = cache_key(params) 
      with lock(key) do 
        CACHE[key] = self.uncached_class.get(params) 
      end 
    end 
  end 
end 


