class TimedCache

def initialize(name, ttl: 60, jitter: 1..5, &block)

def initialize(name, ttl: 60, jitter: 1..5, &block)
  @name   = name
  @ttl    = ttl
  @jitter = jitter
  block or raise ArgumentError, 'block is required'
  @block = block
  @redis = Redis.new
end

def namespaced(key)

def namespaced(key)
  "timed_cache:#{key}"
end

def new_value(now)

def new_value(now)
  Value.new(@block.(), now.to_i)
end

def stored_value

def stored_value
  @redis.get(namespaced(@name)).full? { |s| ::JSON.parse(s, create_additions: true) rescue nil }
end

def value

def value
  now = Time.now
  if stored = stored_value
    if (now - @ttl).to_i >= stored.timestamp
      Thread.new {
        sleep @jitter
        if stored_value.timestamp <= stored.timestamp
          @redis.set namespaced(@name), new_value(now).to_json
        end
      }
    end
    stored.value
  else
    nv = new_value(now)
    @redis.set namespaced(@name), nv.to_json
    nv.value
  end
end