Class: RedisMemo::Cache

Inherits:
ActiveSupport::Cache::RedisCacheStore
  • Object
show all
Defined in:
lib/redis_memo/cache.rb

Defined Under Namespace

Classes: Rescuable

Constant Summary collapse

THREAD_KEY_LOCAL_CACHE =
:__redis_memo_cache_local_cache__
THREAD_KEY_LOCAL_DEPENDENCY_CACHE =
:__redis_memo_local_cache_dependency_cache__
THREAD_KEY_RAISE_ERROR =
:__redis_memo_cache_raise_error__
@@redis =
nil
@@redis_store =
nil
@@redis_store_error_handler =
proc do |method:, exception:, returning:|
  RedisMemo::DefaultOptions.redis_error_handler&.call(exception, method)
  RedisMemo::DefaultOptions.logger&.warn(exception.full_message)
   if Thread.current[THREAD_KEY_RAISE_ERROR]
    raise RedisMemo::Cache::Rescuable
  else
    returning
  end
end

Class Method Summary collapse

Class Method Details

.local_cacheObject

We use our own local_cache instead of the one from RedisCacheStore, because the local_cache in RedisCacheStore stores a dumped ActiveSupport::Cache::Entry object – which is slower comparing to a simple hash storing object references



50
51
52
# File 'lib/redis_memo/cache.rb', line 50

def self.local_cache
  Thread.current[THREAD_KEY_LOCAL_CACHE]
end

.local_dependency_cacheObject



54
55
56
# File 'lib/redis_memo/cache.rb', line 54

def self.local_dependency_cache
  Thread.current[THREAD_KEY_LOCAL_DEPENDENCY_CACHE]
end

.read_multi(*keys, raw: false, raise_error: false) ⇒ Object

RedisCacheStore doesn’t read from the local cache before reading from redis



69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
# File 'lib/redis_memo/cache.rb', line 69

def read_multi(*keys, raw: false, raise_error: false)
  return {} if keys.empty?

  Thread.current[THREAD_KEY_RAISE_ERROR] = raise_error

  local_entries = local_cache&.slice(*keys) || {}

  keys_to_fetch = keys
  keys_to_fetch -= local_entries.keys unless local_entries.empty?
  return local_entries if keys_to_fetch.empty?

  remote_entries = redis_store.read_multi(*keys_to_fetch, raw: raw)
  local_cache&.merge!(remote_entries)

  if local_entries.empty?
    remote_entries
  else
    local_entries.merge!(remote_entries)
  end
end

.redisObject



27
28
29
30
31
32
33
34
# File 'lib/redis_memo/cache.rb', line 27

def self.redis
  @@redis ||=
    if RedisMemo::DefaultOptions.connection_pool
      RedisMemo::ConnectionPool.new(**RedisMemo::DefaultOptions.connection_pool)
    else
      RedisMemo::DefaultOptions.redis
    end
end

.redis_storeObject



36
37
38
39
40
41
42
43
44
# File 'lib/redis_memo/cache.rb', line 36

def self.redis_store
  @@redis_store ||= new(
    compress: RedisMemo::DefaultOptions.compress,
    compress_threshold: RedisMemo::DefaultOptions.compress_threshold,
    error_handler: @@redis_store_error_handler,
    expires_in: RedisMemo::DefaultOptions.expires_in,
    redis: redis,
  )
end

.with_local_cache(&blk) ⇒ Object



59
60
61
62
63
64
65
66
# File 'lib/redis_memo/cache.rb', line 59

def with_local_cache(&blk)
  Thread.current[THREAD_KEY_LOCAL_CACHE] = {}
  Thread.current[THREAD_KEY_LOCAL_DEPENDENCY_CACHE] = {}
  blk.call
ensure
  Thread.current[THREAD_KEY_LOCAL_CACHE] = nil
  Thread.current[THREAD_KEY_LOCAL_DEPENDENCY_CACHE] = nil
end

.write(key, value, disable_async: false, raise_error: false, **options) ⇒ Object



90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
# File 'lib/redis_memo/cache.rb', line 90

def write(key, value, disable_async: false, raise_error: false, **options)
  Thread.current[THREAD_KEY_RAISE_ERROR] = raise_error

  if local_cache
    local_cache[key] = value
  end

  async = RedisMemo::DefaultOptions.async
  if async.nil? || disable_async
    redis_store.write(key, value, **options)
  else
    async.call do
      Thread.current[THREAD_KEY_RAISE_ERROR] = raise_error
      redis_store.write(key, value, **options)
    end
  end
end