Module: Legion::Cache::Helper

Includes:
Logging::Helper
Defined in:
lib/legion/cache/helper.rb

Constant Summary collapse

FALLBACK_TTL =
3600

Instance Method Summary collapse

Instance Method Details

#cache_connected?Boolean

— Status —

Returns:

  • (Boolean)


230
231
232
# File 'lib/legion/cache/helper.rb', line 230

def cache_connected?
  Legion::Cache.connected?
end

#cache_default_ttlObject

— TTL Resolution — Override in your LEX to set a custom default TTL for the extension. Resolution chain: per-call ttl: kwarg -> LEX override -> Settings -> FALLBACK_TTL



15
16
17
18
19
20
21
22
# File 'lib/legion/cache/helper.rb', line 15

def cache_default_ttl
  return FALLBACK_TTL unless defined?(Legion::Settings)

  Legion::Settings.dig(:cache, :default_ttl) || FALLBACK_TTL
rescue StandardError => e
  handle_exception(e, level: :warn, handled: true, operation: :cache_default_ttl)
  FALLBACK_TTL
end

#cache_delete(key) ⇒ Object



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

def cache_delete(key)
  Legion::Cache.delete(cache_namespace + key, async: false)
end

#cache_exist?(key) ⇒ Boolean

Returns:

  • (Boolean)


59
60
61
# File 'lib/legion/cache/helper.rb', line 59

def cache_exist?(key)
  !Legion::Cache.get(cache_namespace + key).nil?
end

#cache_expire(key, seconds) ⇒ Object

Sets TTL on a key. No-op on Memcached (TTL is set at write time).



194
195
196
197
198
199
200
201
# File 'lib/legion/cache/helper.rb', line 194

def cache_expire(key, seconds)
  return false unless cache_redis?

  Legion::Cache::RedisHash.expire(cache_namespace + key, seconds)
rescue StandardError => e
  log_cache_error('cache_expire', e)
  false
end

#cache_fetch(key, ttl: nil) ⇒ Object



54
55
56
57
# File 'lib/legion/cache/helper.rb', line 54

def cache_fetch(key, ttl: nil, &)
  effective_ttl = ttl || cache_default_ttl
  Legion::Cache.fetch(cache_namespace + key, ttl: effective_ttl, &)
end

#cache_get(key) ⇒ Object



46
47
48
# File 'lib/legion/cache/helper.rb', line 46

def cache_get(key)
  Legion::Cache.get(cache_namespace + key)
end

#cache_hdel(key, *fields) ⇒ Object



149
150
151
152
153
154
155
156
157
158
# File 'lib/legion/cache/helper.rb', line 149

def cache_hdel(key, *fields)
  if cache_redis?
    Legion::Cache::RedisHash.hdel(cache_namespace + key, *fields)
  else
    memcached_hash_delete_fields(cache_namespace + key, fields)
  end
rescue StandardError => e
  log_cache_error('cache_hdel', e)
  0
end

#cache_hgetall(key) ⇒ Object



138
139
140
141
142
143
144
145
146
147
# File 'lib/legion/cache/helper.rb', line 138

def cache_hgetall(key)
  if cache_redis?
    Legion::Cache::RedisHash.hgetall(cache_namespace + key)
  else
    memcached_hash_load(cache_namespace + key)
  end
rescue StandardError => e
  log_cache_error('cache_hgetall', e)
  nil
end

#cache_hset(key, hash) ⇒ Object

— RedisHash Helpers (shared tier) — Issue #4: namespaced wrappers for RedisHash operations with Memcached fallback



127
128
129
130
131
132
133
134
135
136
# File 'lib/legion/cache/helper.rb', line 127

def cache_hset(key, hash)
  if cache_redis?
    Legion::Cache::RedisHash.hset(cache_namespace + key, hash)
  else
    memcached_hash_merge(cache_namespace + key, hash)
  end
rescue StandardError => e
  log_cache_error('cache_hset', e)
  false
end

#cache_mget(*keys) ⇒ Object

Returns a Hash of { key => value } pairs. Prefixes all keys with cache_namespace. Delegates to Legion::Cache.mget on Redis; falls back to sequential gets on Memcached.



68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
# File 'lib/legion/cache/helper.rb', line 68

def cache_mget(*keys)
  keys = keys.flatten
  return {} if keys.empty?

  namespaced = keys.map { |k| cache_namespace + k }

  if cache_redis?
    raw = Legion::Cache.mget(*namespaced)
    keys.to_h { |k| [k, raw[cache_namespace + k]] }
  else
    keys.to_h { |k| [k, Legion::Cache.get(cache_namespace + k)] }
  end
rescue StandardError => e
  log_cache_error('cache_mget', e)
  {}
end

#cache_mset(hash, ttl: nil) ⇒ Object

Stores multiple key-value pairs. Accepts a Hash of { key => value }. TTL follows the same resolution chain as cache_set. Delegates to Legion::Cache.mset on Redis; falls back to sequential sets on Memcached.



88
89
90
91
92
93
94
95
96
97
98
# File 'lib/legion/cache/helper.rb', line 88

def cache_mset(hash, ttl: nil)
  return true if hash.empty?

  effective_ttl = ttl || cache_default_ttl

  hash.each { |k, v| Legion::Cache.set(cache_namespace + k, v, ttl: effective_ttl, async: false) }
  true
rescue StandardError => e
  log_cache_error('cache_mset', e)
  false
end

#cache_namespaceObject

— Namespace —



35
36
37
# File 'lib/legion/cache/helper.rb', line 35

def cache_namespace
  @cache_namespace ||= derive_cache_namespace
end

#cache_pool_availableObject



249
250
251
252
253
254
255
256
# File 'lib/legion/cache/helper.rb', line 249

def cache_pool_available
  return 0 unless cache_connected?

  Legion::Cache.available
rescue StandardError => e
  handle_exception(e, level: :warn, handled: true, operation: :cache_pool_available)
  0
end

#cache_pool_sizeObject

— Pool Info —



240
241
242
243
244
245
246
247
# File 'lib/legion/cache/helper.rb', line 240

def cache_pool_size
  return 0 unless cache_connected?

  Legion::Cache.pool_size
rescue StandardError => e
  handle_exception(e, level: :warn, handled: true, operation: :cache_pool_size)
  0
end

#cache_set(key, value, ttl: nil, phi: false) ⇒ Object

— Core Operations (shared tier) —



41
42
43
44
# File 'lib/legion/cache/helper.rb', line 41

def cache_set(key, value, ttl: nil, phi: false)
  effective_ttl = ttl || cache_default_ttl
  Legion::Cache.set(cache_namespace + key, value, ttl: effective_ttl, async: false, phi: phi)
end

#cache_zadd(key, score, member) ⇒ Object



160
161
162
163
164
165
166
167
168
169
# File 'lib/legion/cache/helper.rb', line 160

def cache_zadd(key, score, member)
  raise_sorted_set_unsupported('cache_zadd') unless cache_redis?

  Legion::Cache::RedisHash.zadd(cache_namespace + key, score, member)
rescue NotImplementedError
  raise
rescue StandardError => e
  log_cache_error('cache_zadd', e)
  false
end

#cache_zrangebyscore(key, min, max, limit: nil) ⇒ Object



171
172
173
174
175
176
177
178
179
180
# File 'lib/legion/cache/helper.rb', line 171

def cache_zrangebyscore(key, min, max, limit: nil)
  raise_sorted_set_unsupported('cache_zrangebyscore') unless cache_redis?

  Legion::Cache::RedisHash.zrangebyscore(cache_namespace + key, min, max, limit: limit)
rescue NotImplementedError
  raise
rescue StandardError => e
  log_cache_error('cache_zrangebyscore', e)
  []
end

#cache_zrem(key, member) ⇒ Object



182
183
184
185
186
187
188
189
190
191
# File 'lib/legion/cache/helper.rb', line 182

def cache_zrem(key, member)
  raise_sorted_set_unsupported('cache_zrem') unless cache_redis?

  Legion::Cache::RedisHash.zrem(cache_namespace + key, member)
rescue NotImplementedError
  raise
rescue StandardError => e
  log_cache_error('cache_zrem', e)
  false
end

#local_cache_connected?Boolean

Returns:

  • (Boolean)


234
235
236
# File 'lib/legion/cache/helper.rb', line 234

def local_cache_connected?
  Legion::Cache::Local.connected?
end

#local_cache_default_ttlObject



24
25
26
27
28
29
30
31
# File 'lib/legion/cache/helper.rb', line 24

def local_cache_default_ttl
  return cache_default_ttl unless defined?(Legion::Settings)

  Legion::Settings.dig(:cache_local, :default_ttl) || cache_default_ttl
rescue StandardError => e
  handle_exception(e, level: :warn, handled: true, operation: :local_cache_default_ttl)
  cache_default_ttl
end

#local_cache_delete(key) ⇒ Object



215
216
217
# File 'lib/legion/cache/helper.rb', line 215

def local_cache_delete(key)
  Legion::Cache::Local.delete(cache_namespace + key, async: false)
end

#local_cache_exist?(key) ⇒ Boolean

Returns:

  • (Boolean)


224
225
226
# File 'lib/legion/cache/helper.rb', line 224

def local_cache_exist?(key)
  !Legion::Cache::Local.get(cache_namespace + key).nil?
end

#local_cache_fetch(key, ttl: nil) ⇒ Object



219
220
221
222
# File 'lib/legion/cache/helper.rb', line 219

def local_cache_fetch(key, ttl: nil, &)
  effective_ttl = ttl || local_cache_default_ttl
  Legion::Cache::Local.fetch(cache_namespace + key, ttl: effective_ttl, &)
end

#local_cache_get(key) ⇒ Object



211
212
213
# File 'lib/legion/cache/helper.rb', line 211

def local_cache_get(key)
  Legion::Cache::Local.get(cache_namespace + key)
end

#local_cache_mget(*keys) ⇒ Object

— Batch Operations (local tier) —



102
103
104
105
106
107
108
109
110
# File 'lib/legion/cache/helper.rb', line 102

def local_cache_mget(*keys)
  keys = keys.flatten
  return {} if keys.empty?

  keys.to_h { |k| [k, Legion::Cache::Local.get(cache_namespace + k)] }
rescue StandardError => e
  log_cache_error('local_cache_mget', e)
  {}
end

#local_cache_mset(hash, ttl: nil) ⇒ Object



112
113
114
115
116
117
118
119
120
121
122
# File 'lib/legion/cache/helper.rb', line 112

def local_cache_mset(hash, ttl: nil)
  return true if hash.empty?

  effective_ttl = ttl || local_cache_default_ttl

  hash.each { |k, v| Legion::Cache::Local.set(cache_namespace + k, v, ttl: effective_ttl, async: false) }
  true
rescue StandardError => e
  log_cache_error('local_cache_mset', e)
  false
end

#local_cache_pool_availableObject



267
268
269
270
271
272
273
274
# File 'lib/legion/cache/helper.rb', line 267

def local_cache_pool_available
  return 0 unless local_cache_connected?

  Legion::Cache::Local.available
rescue StandardError => e
  handle_exception(e, level: :warn, handled: true, operation: :local_cache_pool_available)
  0
end

#local_cache_pool_sizeObject



258
259
260
261
262
263
264
265
# File 'lib/legion/cache/helper.rb', line 258

def local_cache_pool_size
  return 0 unless local_cache_connected?

  Legion::Cache::Local.pool_size
rescue StandardError => e
  handle_exception(e, level: :warn, handled: true, operation: :local_cache_pool_size)
  0
end

#local_cache_set(key, value, ttl: nil, phi: false) ⇒ Object

— Core Operations (local tier) —



205
206
207
208
209
# File 'lib/legion/cache/helper.rb', line 205

def local_cache_set(key, value, ttl: nil, phi: false)
  effective_ttl = ttl || local_cache_default_ttl
  effective_ttl = Legion::Cache.enforce_phi_ttl(effective_ttl, phi: phi)
  Legion::Cache::Local.set(cache_namespace + key, value, ttl: effective_ttl, async: false)
end