class Cloudtasker::RedisClient

A wrapper with helper methods for redis

Constants

DEFAULT_POOL_SIZE

Default pool size used for Redis

DEFAULT_POOL_TIMEOUT
LOCK_DURATION
LOCK_KEY_PREFIX

Suffix added to cache keys when locking them

LOCK_WAIT_DURATION

Public Class Methods

client() click to toggle source
# File lib/cloudtasker/redis_client.rb, line 18
def self.client
  @client ||= begin
    pool_size = Cloudtasker.config.redis&.dig(:pool_size) || DEFAULT_POOL_SIZE
    pool_timeout = Cloudtasker.config.redis&.dig(:pool_timeout) || DEFAULT_POOL_TIMEOUT
    ConnectionPool.new(size: pool_size, timeout: pool_timeout) do
      Redis.new(Cloudtasker.config.redis || {})
    end
  end
end

Public Instance Methods

clear() click to toggle source

Clear all redis keys

@return [Integer] The number of keys deleted

# File lib/cloudtasker/redis_client.rb, line 103
def clear
  all_keys = keys
  return 0 if all_keys.empty?

  # Delete all keys
  del(*all_keys)
end
client() click to toggle source

Return the underlying redis client.

@return [Redis] The redis client.

# File lib/cloudtasker/redis_client.rb, line 33
def client
  @client ||= self.class.client
end
fetch(key) click to toggle source

Get a cache entry and parse it as JSON.

@param [String, Symbol] key The cache key to fetch.

@return [Hash, Array] The content of the cache key, parsed as JSON.

# File lib/cloudtasker/redis_client.rb, line 44
def fetch(key)
  return nil unless (val = get(key.to_s))

  JSON.parse(val, symbolize_names: true)
rescue JSON::ParserError
  nil
end
method_missing(name, *args, &block) click to toggle source

Delegate all methods to the redis client.

@param [String, Symbol] name The method to delegate. @param [Array<any>] *args The list of method arguments. @param [Proc] &block Block passed to the method.

@return [Any] The method return value

Calls superclass method
# File lib/cloudtasker/redis_client.rb, line 144
def method_missing(name, *args, &block)
  if Redis.method_defined?(name)
    client.with { |c| c.send(name, *args, &block) }
  else
    super
  end
end
respond_to_missing?(name, include_private = false) click to toggle source

Check if the class respond to a certain method.

@param [String, Symbol] name The name of the method. @param [Boolean] include_private Whether to check private methods or not. Default to false.

@return [Boolean] Return true if the class respond to this method.

Calls superclass method
# File lib/cloudtasker/redis_client.rb, line 160
def respond_to_missing?(name, include_private = false)
  Redis.method_defined?(name) || super
end
with_lock(cache_key, max_wait: nil) { || ... } click to toggle source

Acquire a lock on a cache entry.

Locks are enforced to be short-lived (2s). The yielded block should limit its logic to short operations (e.g. redis get/set).

@example

redis = RedisClient.new
redis.with_lock('foo')
  content = redis.fetch('foo')
  redis.set(content.merge(bar: 'bar).to_json)
end

@param [String] cache_key The cache key to access. @param [Integer] max_wait The number of seconds after which the lock will be cleared anyway.

# File lib/cloudtasker/redis_client.rb, line 80
def with_lock(cache_key, max_wait: nil)
  return nil unless cache_key

  # Set max wait
  max_wait = (max_wait || LOCK_DURATION).to_i

  # Wait to acquire lock
  lock_key = [LOCK_KEY_PREFIX, cache_key].join('/')
  client.with do |conn|
    sleep(LOCK_WAIT_DURATION) until conn.set(lock_key, true, nx: true, ex: max_wait)
  end

  # yield content
  yield
ensure
  del(lock_key)
end
write(key, content) click to toggle source

Write a cache entry as JSON.

@param [String, Symbol] key The cache key to write. @param [Hash, Array] content The content to write.

@return [String] Redis response code.

# File lib/cloudtasker/redis_client.rb, line 60
def write(key, content)
  set(key.to_s, content.to_json)
end