Module: Legion::Cache

Extended by:
Logging::Helper
Defined in:
lib/legion/cache.rb,
lib/legion/cache/pool.rb,
lib/legion/cache/local.rb,
lib/legion/cache/redis.rb,
lib/legion/cache/helper.rb,
lib/legion/cache/memory.rb,
lib/legion/cache/version.rb,
lib/legion/cache/settings.rb,
lib/legion/cache/cacheable.rb,
lib/legion/cache/memcached.rb,
lib/legion/cache/redis_hash.rb,
lib/legion/cache/reconnector.rb,
lib/legion/cache/async_writer.rb

Defined Under Namespace

Modules: Cacheable, Helper, Local, Memcached, Memory, Pool, Redis, RedisHash, Settings Classes: AsyncWriter, Reconnector

Constant Summary collapse

VERSION =
'1.4.2'

Class Method Summary collapse

Class Method Details

.availableObject



327
328
329
330
331
332
333
# File 'lib/legion/cache.rb', line 327

def available
  return Legion::Cache::Memory.available if using_memory?
  return Legion::Cache::Local.available if using_local?

  configure_shared_adapter!
  super
end

.client(**opts) ⇒ Object



129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
# File 'lib/legion/cache.rb', line 129

def client(**opts)
  if ENV['LEGION_MODE'] == 'lite'
    Legion::Cache::Memory.setup unless Legion::Cache::Memory.connected?
    @using_memory.make_true
    @using_local.make_false
    @connected.make_true
    @active_shared_driver = nil
    Legion::Settings[:cache][:connected] = true if defined?(Legion::Settings)
    return Legion::Cache::Memory.client
  end

  configure_shared_adapter!(opts[:driver])
  @using_memory.make_false
  @using_local.make_false
  result = super
  # super (Pool) sets @connected to a plain boolean; restore AtomicBoolean
  @connected = Concurrent::AtomicBoolean.new(true)
  Legion::Settings[:cache][:connected] = true if defined?(Legion::Settings)
  result
rescue StandardError
  @connected = Concurrent::AtomicBoolean.new(false)
  Legion::Settings[:cache][:connected] = false if defined?(Legion::Settings)
  raise
end

.closeObject



283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
# File 'lib/legion/cache.rb', line 283

def close
  if using_memory?
    Legion::Cache::Memory.shutdown
    @using_memory.make_false
    @connected.make_false
    Legion::Settings[:cache][:connected] = false if defined?(Legion::Settings)
    return false
  end

  if using_local?
    Legion::Cache::Local.close
    @using_local.make_false
    @connected.make_false
    Legion::Settings[:cache][:connected] = false if defined?(Legion::Settings)
    return false
  end

  return false unless instance_variable_defined?(:@client) && @client

  configure_shared_adapter!
  result = super
  @connected = Concurrent::AtomicBoolean.new(false)
  Legion::Settings[:cache][:connected] = false if defined?(Legion::Settings)
  result
end

.connected?Boolean

Returns:

  • (Boolean)


39
40
41
# File 'lib/legion/cache.rb', line 39

def connected?
  @connected&.true? || false
end

.delete(key, async: true) ⇒ Object



224
225
226
227
228
229
230
231
# File 'lib/legion/cache.rb', line 224

def delete(key, async: true)
  if async && async_writer.running?
    async_writer.enqueue { delete_internal(key) }
    true
  else
    delete_internal(key)
  end
end

.delete_sync(key) ⇒ Object



233
234
235
236
237
238
239
240
# File 'lib/legion/cache.rb', line 233

def delete_sync(key)
  return Legion::Cache::Memory.delete_sync(key) if using_memory?
  return Legion::Cache::Local.delete_sync(key) if using_local?
  return Legion::Cache::Local.delete_sync(key) if failback_to_local?

  configure_shared_adapter!
  super
end

.driver_nameObject



43
44
45
46
47
48
# File 'lib/legion/cache.rb', line 43

def driver_name
  return 'memory' if using_memory?
  return 'local' if using_local?

  @active_shared_driver || configured_shared_driver
end

.enabled?Boolean

Returns:

  • (Boolean)


30
31
32
33
34
35
36
37
# File 'lib/legion/cache.rb', line 30

def enabled?
  return true unless defined?(Legion::Settings)

  Legion::Settings.dig(:cache, :enabled) != false
rescue StandardError => e
  handle_exception(e, level: :warn, handled: true, operation: :cache_enabled)
  true
end

.enforce_phi_ttl(ttl, phi: false) ⇒ Object



175
176
177
178
179
180
# File 'lib/legion/cache.rb', line 175

def enforce_phi_ttl(ttl, phi: false, **)
  return ttl unless phi == true

  max = phi_max_ttl
  [ttl, max].min
end

.fetch(key, ttl: nil) ⇒ Object



215
216
217
218
219
220
221
222
# File 'lib/legion/cache.rb', line 215

def fetch(key, ttl: nil, &)
  return Legion::Cache::Memory.fetch(key, ttl: ttl, &) if using_memory?
  return Legion::Cache::Local.fetch(key, ttl: ttl, &) if using_local?
  return Legion::Cache::Local.fetch(key, ttl: ttl, &) if failback_to_local?

  configure_shared_adapter!
  super
end

.flushObject



242
243
244
245
246
247
248
249
# File 'lib/legion/cache.rb', line 242

def flush
  return Legion::Cache::Memory.flush if using_memory?
  return Legion::Cache::Local.flush if using_local?
  return Legion::Cache::Local.flush if failback_to_local?

  configure_shared_adapter!
  super
end

.get(key) ⇒ Object



154
155
156
157
158
159
160
161
162
163
164
# File 'lib/legion/cache.rb', line 154

def get(key)
  return Legion::Cache::Memory.get(key) if using_memory?
  return Legion::Cache::Local.get(key) if using_local?
  return Legion::Cache::Local.get(key) if failback_to_local?

  configure_shared_adapter!
  super
rescue StandardError => e
  handle_exception(e, level: :warn, handled: true, operation: :cache_get, key: key)
  nil
end

.localObject



113
114
115
# File 'lib/legion/cache.rb', line 113

def local
  Legion::Cache::Local
end

.mget(*keys) ⇒ Object



251
252
253
254
255
256
257
258
259
260
# File 'lib/legion/cache.rb', line 251

def mget(*keys)
  keys = keys.flatten
  return {} if keys.empty?
  return keys.to_h { |key| [key, Legion::Cache::Memory.get(key)] } if using_memory?
  return Legion::Cache::Local.mget(*keys) if using_local?
  return Legion::Cache::Local.mget(*keys) if failback_to_local?

  configure_shared_adapter!
  super
end

.mset(hash, ttl: nil, async: true) ⇒ Object



262
263
264
265
266
267
268
269
270
271
# File 'lib/legion/cache.rb', line 262

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

  if async && async_writer.running?
    async_writer.enqueue { mset_internal(hash, ttl: ttl) }
    true
  else
    mset_internal(hash, ttl: ttl)
  end
end

.mset_sync(hash, ttl: nil) ⇒ Object



273
274
275
276
277
278
279
280
281
# File 'lib/legion/cache.rb', line 273

def mset_sync(hash, ttl: nil, **)
  return true if hash.empty?
  return hash.each { |key, value| Legion::Cache::Memory.set_sync(key, value, ttl: ttl) } && true if using_memory?
  return Legion::Cache::Local.mset(hash, ttl: ttl) if using_local?
  return Legion::Cache::Local.mset(hash, ttl: ttl) if failback_to_local?

  configure_shared_adapter!
  super
end

.phi_max_ttlObject



166
167
168
169
170
171
172
173
# File 'lib/legion/cache.rb', line 166

def phi_max_ttl
  return 3600 unless defined?(Legion::Settings)

  Legion::Settings.dig(:cache, :compliance, :phi_max_ttl) || 3600
rescue StandardError => e
  handle_exception(e, level: :warn, handled: true, operation: :cache_phi_max_ttl)
  3600
end

.poolObject



117
118
119
# File 'lib/legion/cache.rb', line 117

def pool
  @client
end

.pool_sizeObject



335
336
337
338
339
340
341
# File 'lib/legion/cache.rb', line 335

def pool_size
  return Legion::Cache::Memory.size if using_memory?
  return Legion::Cache::Local.pool_size if using_local?

  configure_shared_adapter!
  super
end

.restart(**opts) ⇒ Object



309
310
311
312
313
314
315
316
317
# File 'lib/legion/cache.rb', line 309

def restart(**opts)
  configure_shared_adapter!(opts[:driver])
  @using_memory.make_false
  @using_local.make_false
  result = super
  @connected = Concurrent::AtomicBoolean.new(true)
  Legion::Settings[:cache][:connected] = true if defined?(Legion::Settings)
  result
end

.set(key, value, ttl: nil, async: true, phi: false) ⇒ Object



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

def set(key, value, ttl: nil, async: true, phi: false)
  effective_ttl = resolve_ttl(ttl, phi: phi)

  if async && async_writer.running?
    async_writer.enqueue { set_internal(key, value, ttl: effective_ttl) }
    true
  else
    set_internal(key, value, ttl: effective_ttl)
  end
end

.set_nx(key, value, ttl: nil) ⇒ Object



193
194
195
196
197
198
199
200
201
202
203
204
# File 'lib/legion/cache.rb', line 193

def set_nx(key, value, ttl: nil)
  effective_ttl = resolve_ttl(ttl)
  return Legion::Cache::Memory.set_nx(key, value, ttl: effective_ttl) if using_memory?
  return Legion::Cache::Local.set_nx(key, value, ttl: effective_ttl) if using_local?
  return Legion::Cache::Local.set_nx(key, value, ttl: effective_ttl) if failback_to_local?

  configure_shared_adapter!
  super
rescue StandardError => e
  handle_exception(e, level: :warn, handled: true, operation: :cache_set_nx, key: key)
  false
end

.set_sync(key, value, ttl: nil) ⇒ Object



206
207
208
209
210
211
212
213
# File 'lib/legion/cache.rb', line 206

def set_sync(key, value, ttl: nil, **)
  return Legion::Cache::Memory.set_sync(key, value, ttl: ttl) if using_memory?
  return Legion::Cache::Local.set_sync(key, value, ttl: ttl) if using_local?
  return Legion::Cache::Local.set_sync(key, value, ttl: ttl) if failback_to_local?

  configure_shared_adapter!
  super
end

.setupObject



72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
# File 'lib/legion/cache.rb', line 72

def setup(**)
  return unless enabled?
  return Legion::Settings[:cache][:connected] = true if connected?

  @setup_at = Time.now

  async_writer.start

  if ENV['LEGION_MODE'] == 'lite'
    Legion::Cache::Memory.setup
    @using_memory.make_true
    @connected.make_true
    Legion::Settings[:cache][:connected] = true
    log.info 'Legion::Cache using in-memory adapter (lite mode)'
    return
  end

  log.debug { "Legion::Cache setup driver=#{Legion::Settings[:cache][:driver]} servers=#{Array(Legion::Settings[:cache][:servers]).size}" }
  setup_local
  setup_shared(**)
end

.shutdownObject



94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
# File 'lib/legion/cache.rb', line 94

def shutdown
  log.info 'Shutting down Legion::Cache'
  # 1. Drain async writer FIRST (while pool is still alive)
  async_writer.stop(timeout: configured_shutdown_timeout)
  # 2. Stop reconnector
  stop_reconnector
  # 3. Now close pools
  if using_memory?
    Legion::Cache::Memory.shutdown
  else
    close unless using_local?
    Legion::Cache::Local.shutdown if Legion::Cache::Local.connected?
  end
  @using_local.make_false
  @using_memory.make_false
  @connected.make_false
  Legion::Settings[:cache][:connected] = false
end

.sizeObject



319
320
321
322
323
324
325
# File 'lib/legion/cache.rb', line 319

def size
  return Legion::Cache::Memory.size if using_memory?
  return Legion::Cache::Local.size if using_local?

  configure_shared_adapter!
  super
end

.statsObject



50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
# File 'lib/legion/cache.rb', line 50

def stats
  {
    driver:             driver_name,
    servers:            resolved_servers,
    enabled:            enabled?,
    connected:          connected?,
    using_local:        using_local?,
    using_memory:       using_memory?,
    pool_size:          safe_pool_size,
    pool_available:     safe_pool_available,
    async_pool_size:    async_writer_pool_size,
    async_queue_depth:  async_writer_queue_depth,
    async_processed:    async_writer_processed_count,
    async_failed:       async_writer_failed_count,
    reconnect_attempts: reconnector_attempts,
    uptime:             uptime_seconds
  }.freeze
rescue StandardError => e
  handle_exception(e, level: :warn, handled: true, operation: :cache_stats)
  { error: e.message }.freeze
end

.timeoutObject



343
344
345
346
347
348
349
# File 'lib/legion/cache.rb', line 343

def timeout
  return 0 if using_memory?
  return Legion::Cache::Local.timeout if using_local?

  configure_shared_adapter!
  super
end

.using_local?Boolean

Returns:

  • (Boolean)


121
122
123
# File 'lib/legion/cache.rb', line 121

def using_local?
  @using_local&.true? || false
end

.using_memory?Boolean

Returns:

  • (Boolean)


125
126
127
# File 'lib/legion/cache.rb', line 125

def using_memory?
  @using_memory&.true? || false
end