legion-cache 1.3.20 → 1.3.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9f7b5b5352d50ed073af5771dd82ce824db96f0cc508beb942250dfc447428df
4
- data.tar.gz: 42f6988a094eaaf4ba63c0b91ac35dd614c91bba256f574e2b97a93df4d63686
3
+ metadata.gz: 02b45cdf2162b9906e9e51c9ba9dbc205b38b65813844100223b0985945352da
4
+ data.tar.gz: 2a590f3f1e8d615165955c8ded6ed35c3057abb308bcef04b5d97fd025351800
5
5
  SHA512:
6
- metadata.gz: 155a80836657e0f8e0d1260ad02d2082fa82f80fed10f7f861d794fc47e7538dbe70305c2561d99e457fe5e8ee2c40d09985bd1a5c8351cb9a2cc26913f43804
7
- data.tar.gz: c17d8a5c0a71f85488713ccbff577d5b7beb4f7a88126a393c1978d7f6a89c20e71f3ede41ce8e7d1f214664a24c72eb7dba3f2d2d8dd5a09363c0b7cda66ce2
6
+ metadata.gz: 5938e92b24a66f18169f00544aa96c3c88d80ca820807cd2ee8f08d6308fc4cd939f01e5e47d8b5ad0537c0a1ea450515641f21ad582c8726c92be0516511cec
7
+ data.tar.gz: 04de2781334fb61676f5943a39c85a34ddf29db2f5cbec83b9afa9b9b08b0b9e2bd532667ceef3e2e759fb821a063d4a12cf27b592860da098bdf6290dd55483
data/CHANGELOG.md CHANGED
@@ -2,6 +2,19 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [1.3.21] - 2026-04-02
6
+
7
+ ### Fixed
8
+ - Preserve `fetch` block behavior across shared, local, memory, and Redis cache paths; local-cache failures now fall back to the in-process cache and cached `false` values are retained correctly
9
+ - Move shared adapter selection to runtime setup/client calls, register cache defaults through `Legion::Cache::Settings`, and normalize IPv4/hostname/IPv6 server addresses consistently
10
+ - Restrict Redis hash/sorted-set helpers to the actual Redis backend and enforce documented TTL behavior for helper batch writes
11
+ - Make the default `bundle exec rspec` suite hermetic by excluding service-backed integration specs unless `RUN_INTEGRATION_SPECS=1`
12
+
13
+ ### Changed
14
+ - Uplift cache logging internals to `Legion::Logging::Helper`, replacing direct logger calls with helper-provided `log` usage across cache runtime modules
15
+ - Route rescued cache adapter/helper/setup failures through `handle_exception` and expand runtime `info`/`debug`/`error` coverage for shared, local, memory, pool, and RedisHash flows
16
+ - Require `legion-logging >= 1.5.0` at runtime so helper exception handling is always available
17
+
5
18
  ## [1.3.20] - 2026-03-31
6
19
 
7
20
  ### Fixed
data/legion-cache.gemspec CHANGED
@@ -28,7 +28,7 @@ Gem::Specification.new do |spec|
28
28
 
29
29
  spec.add_dependency 'connection_pool', '>= 2.4'
30
30
  spec.add_dependency 'dalli', '>= 3.0'
31
- spec.add_dependency 'legion-logging', '>= 1.2.8'
31
+ spec.add_dependency 'legion-logging', '>= 1.5.0'
32
32
  spec.add_dependency 'legion-settings', '>= 1.3.12'
33
33
  spec.add_dependency 'redis', '>= 5.0'
34
34
  end
@@ -1,10 +1,15 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'digest'
4
+ require 'legion/logging/helper'
4
5
 
5
6
  module Legion
6
7
  module Cache
7
8
  module Cacheable
9
+ extend Legion::Logging::Helper
10
+
11
+ LOCAL_CACHE_MISS = Object.new
12
+
8
13
  def self.extended(base)
9
14
  base.instance_variable_set(:@cached_methods, {})
10
15
  end
@@ -29,9 +34,9 @@ module Legion
29
34
  unless bypass_local_method_cache
30
35
  cached = Legion::Cache::Cacheable.cache_read(key, scope: config[:scope])
31
36
  if cached.nil?
32
- Legion::Logging.debug "[cacheable] miss key=#{key}" if defined?(Legion::Logging)
37
+ Legion::Cache::Cacheable.log.debug { "[cacheable] miss key=#{key}" }
33
38
  else
34
- Legion::Logging.debug "[cacheable] hit key=#{key}" if defined?(Legion::Logging)
39
+ Legion::Cache::Cacheable.log.debug { "[cacheable] hit key=#{key}" }
35
40
  return cached
36
41
  end
37
42
  end
@@ -58,7 +63,8 @@ module Legion
58
63
 
59
64
  memory_read(key)
60
65
  else
61
- local_cache_read(key) || memory_read(key)
66
+ result = local_cache_read(key)
67
+ result.equal?(LOCAL_CACHE_MISS) ? memory_read(key) : result
62
68
  end
63
69
  end
64
70
 
@@ -72,7 +78,8 @@ module Legion
72
78
  end
73
79
  else
74
80
  if local_cache_available?
75
- local_cache_write(key, value, ttl)
81
+ result = local_cache_write(key, value, ttl)
82
+ memory_write(key, value, ttl) unless result
76
83
  else
77
84
  memory_write(key, value, ttl)
78
85
  end
@@ -88,12 +95,13 @@ module Legion
88
95
  end
89
96
 
90
97
  def self.local_cache_read(key)
91
- return nil unless local_cache_available?
98
+ return LOCAL_CACHE_MISS unless local_cache_available?
92
99
 
93
- Legion::Cache::Local.get(key)
100
+ result = Legion::Cache::Local.get(key)
101
+ result.nil? ? LOCAL_CACHE_MISS : result
94
102
  rescue StandardError => e
95
- Legion::Logging.warn "[cacheable] local_cache_read failed key=#{key} error=#{e.message}" if defined?(Legion::Logging)
96
- nil
103
+ handle_exception(e, level: :warn, operation: :local_cache_read, key: key)
104
+ LOCAL_CACHE_MISS
97
105
  end
98
106
 
99
107
  def self.local_cache_write(key, value, ttl)
@@ -101,7 +109,7 @@ module Legion
101
109
 
102
110
  Legion::Cache::Local.set(key, value, ttl)
103
111
  rescue StandardError => e
104
- Legion::Logging.warn "[cacheable] local_cache_write failed key=#{key} error=#{e.message}" if defined?(Legion::Logging)
112
+ handle_exception(e, level: :warn, operation: :local_cache_write, key: key, ttl: ttl)
105
113
  nil
106
114
  end
107
115
 
@@ -1,8 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'legion/logging/helper'
4
+
3
5
  module Legion
4
6
  module Cache
5
7
  module Helper
8
+ include Legion::Logging::Helper
9
+
6
10
  FALLBACK_TTL = 60
7
11
 
8
12
  # --- TTL Resolution ---
@@ -12,7 +16,8 @@ module Legion
12
16
  return FALLBACK_TTL unless defined?(Legion::Settings)
13
17
 
14
18
  Legion::Settings.dig(:cache, :default_ttl) || FALLBACK_TTL
15
- rescue StandardError
19
+ rescue StandardError => e
20
+ handle_exception(e, level: :warn, handled: true, operation: :cache_default_ttl)
16
21
  FALLBACK_TTL
17
22
  end
18
23
 
@@ -20,7 +25,8 @@ module Legion
20
25
  return cache_default_ttl unless defined?(Legion::Settings)
21
26
 
22
27
  Legion::Settings.dig(:cache_local, :default_ttl) || cache_default_ttl
23
- rescue StandardError
28
+ rescue StandardError => e
29
+ handle_exception(e, level: :warn, handled: true, operation: :local_cache_default_ttl)
24
30
  cache_default_ttl
25
31
  end
26
32
 
@@ -84,13 +90,8 @@ module Legion
84
90
 
85
91
  effective_ttl = ttl || cache_default_ttl
86
92
 
87
- if cache_redis?
88
- namespaced = hash.transform_keys { |k| cache_namespace + k }
89
- Legion::Cache.mset(namespaced)
90
- else
91
- hash.each { |k, v| Legion::Cache.set(cache_namespace + k, v, effective_ttl) }
92
- true
93
- end
93
+ hash.each { |k, v| Legion::Cache.set(cache_namespace + k, v, effective_ttl) }
94
+ true
94
95
  rescue StandardError => e
95
96
  log_cache_error('cache_mset', e)
96
97
  false
@@ -102,13 +103,7 @@ module Legion
102
103
  keys = keys.flatten
103
104
  return {} if keys.empty?
104
105
 
105
- if local_cache_redis?
106
- namespaced = keys.map { |k| cache_namespace + k }
107
- raw = Legion::Cache::Local.mget(*namespaced)
108
- keys.to_h { |k| [k, raw[cache_namespace + k]] }
109
- else
110
- keys.to_h { |k| [k, Legion::Cache::Local.get(cache_namespace + k)] }
111
- end
106
+ keys.to_h { |k| [k, Legion::Cache::Local.get(cache_namespace + k)] }
112
107
  rescue StandardError => e
113
108
  log_cache_error('local_cache_mget', e)
114
109
  {}
@@ -119,13 +114,8 @@ module Legion
119
114
 
120
115
  effective_ttl = ttl || local_cache_default_ttl
121
116
 
122
- if local_cache_redis?
123
- namespaced = hash.transform_keys { |k| cache_namespace + k }
124
- Legion::Cache::Local.mset(namespaced)
125
- else
126
- hash.each { |k, v| Legion::Cache::Local.set(cache_namespace + k, v, effective_ttl) }
127
- true
128
- end
117
+ hash.each { |k, v| Legion::Cache::Local.set(cache_namespace + k, v, effective_ttl) }
118
+ true
129
119
  rescue StandardError => e
130
120
  log_cache_error('local_cache_mset', e)
131
121
  false
@@ -251,7 +241,8 @@ module Legion
251
241
  return 0 unless cache_connected?
252
242
 
253
243
  Legion::Cache.pool_size
254
- rescue StandardError
244
+ rescue StandardError => e
245
+ handle_exception(e, level: :warn, handled: true, operation: :cache_pool_size)
255
246
  0
256
247
  end
257
248
 
@@ -259,7 +250,8 @@ module Legion
259
250
  return 0 unless cache_connected?
260
251
 
261
252
  Legion::Cache.available
262
- rescue StandardError
253
+ rescue StandardError => e
254
+ handle_exception(e, level: :warn, handled: true, operation: :cache_pool_available)
263
255
  0
264
256
  end
265
257
 
@@ -267,7 +259,8 @@ module Legion
267
259
  return 0 unless local_cache_connected?
268
260
 
269
261
  Legion::Cache::Local.pool_size
270
- rescue StandardError
262
+ rescue StandardError => e
263
+ handle_exception(e, level: :warn, handled: true, operation: :local_cache_pool_size)
271
264
  0
272
265
  end
273
266
 
@@ -275,7 +268,8 @@ module Legion
275
268
  return 0 unless local_cache_connected?
276
269
 
277
270
  Legion::Cache::Local.available
278
- rescue StandardError
271
+ rescue StandardError => e
272
+ handle_exception(e, level: :warn, handled: true, operation: :local_cache_pool_available)
279
273
  0
280
274
  end
281
275
 
@@ -310,8 +304,9 @@ module Legion
310
304
 
311
305
  def local_cache_redis?
312
306
  defined?(Legion::Cache::Local) &&
313
- Legion::Cache::Local.respond_to?(:mget) &&
314
- Legion::Cache::Local.connected?
307
+ Legion::Cache::Local.connected? &&
308
+ Legion::Cache::Local.respond_to?(:driver_name) &&
309
+ Legion::Cache::Local.driver_name == 'redis'
315
310
  end
316
311
 
317
312
  def memcached_hash_merge(full_key, new_fields)
@@ -328,7 +323,8 @@ module Legion
328
323
  parsed = Legion::JSON.load(raw)
329
324
  # Legion::JSON.load returns symbol keys; convert to string keys to mirror Redis hgetall
330
325
  parsed.transform_keys(&:to_s)
331
- rescue StandardError
326
+ rescue StandardError => e
327
+ handle_exception(e, level: :warn, handled: true, operation: :memcached_hash_load, key: full_key)
332
328
  nil
333
329
  end
334
330
 
@@ -349,9 +345,7 @@ module Legion
349
345
  end
350
346
 
351
347
  def log_cache_error(method, error)
352
- return unless defined?(Legion::Logging)
353
-
354
- Legion::Logging.warn "[cache:helper] #{method} failed: #{error.class} — #{error.message}"
348
+ handle_exception(error, level: :warn, operation: method)
355
349
  end
356
350
  end
357
351
  end
@@ -1,11 +1,14 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'legion/logging/helper'
3
4
  require 'legion/cache/settings'
4
5
 
5
6
  module Legion
6
7
  module Cache
7
8
  module Local
8
9
  class << self
10
+ include Legion::Logging::Helper
11
+
9
12
  def setup(**)
10
13
  return if @connected
11
14
 
@@ -13,22 +16,24 @@ module Legion
13
16
  return unless settings[:enabled]
14
17
 
15
18
  driver_name = settings[:driver] || Legion::Cache::Settings.driver
19
+ @driver_name = Legion::Cache::Settings.normalize_driver(driver_name)
16
20
  @driver = build_driver(driver_name)
17
- @driver.client(**settings, **)
21
+ @driver.client(**settings, logger: log, **)
18
22
  @connected = true
19
23
  servers = Array(settings[:servers]).join(', ')
20
- Legion::Logging.info "Legion::Cache::Local connected (#{driver_name}) to #{servers}" if defined?(Legion::Logging)
24
+ log.info "Legion::Cache::Local connected (#{driver_name}) to #{servers}"
21
25
  rescue StandardError => e
22
- Legion::Logging.warn "Legion::Cache::Local setup failed: #{e.message}" if defined?(Legion::Logging)
26
+ handle_exception(e, level: :warn, handled: true, operation: :cache_local_setup, driver: driver_name)
23
27
  @connected = false
24
28
  end
25
29
 
26
30
  def shutdown
27
31
  return unless @connected
28
32
 
29
- Legion::Logging.info 'Shutting down Legion::Cache::Local' if defined?(Legion::Logging)
33
+ log.info 'Shutting down Legion::Cache::Local'
30
34
  @driver&.close
31
35
  @driver = nil
36
+ @driver_name = nil
32
37
  @connected = false
33
38
  end
34
39
 
@@ -36,34 +41,53 @@ module Legion
36
41
  @connected == true
37
42
  end
38
43
 
44
+ def driver_name
45
+ @driver_name || Legion::Cache::Settings.normalize_driver(local_settings[:driver] || Legion::Cache::Settings.driver)
46
+ end
47
+
39
48
  def get(key)
40
49
  result = @driver.get(key)
41
- Legion::Logging.debug "[cache:local] GET #{key} hit=#{!result.nil?}" if defined?(Legion::Logging)
50
+ log.debug "[cache:local] GET #{key} hit=#{!result.nil?}"
42
51
  result
52
+ rescue StandardError => e
53
+ handle_exception(e, level: :warn, handled: false, operation: :cache_local_get, key: key)
54
+ raise
43
55
  end
44
56
 
45
57
  def set(key, value, ttl = 180)
46
58
  result = @driver.set(key, value, ttl)
47
- Legion::Logging.debug "[cache:local] SET #{key} ttl=#{ttl} success=#{result}" if defined?(Legion::Logging)
59
+ log.debug "[cache:local] SET #{key} ttl=#{ttl} success=#{result}"
48
60
  result
61
+ rescue StandardError => e
62
+ handle_exception(e, level: :warn, handled: false, operation: :cache_local_set, key: key, ttl: ttl)
63
+ raise
49
64
  end
50
65
 
51
- def fetch(key, ttl = nil)
52
- result = @driver.fetch(key, ttl)
53
- Legion::Logging.debug "[cache:local] FETCH #{key} hit=#{!result.nil?}" if defined?(Legion::Logging)
66
+ def fetch(key, ttl = nil, &)
67
+ result = @driver.fetch(key, ttl, &)
68
+ log.debug "[cache:local] FETCH #{key} hit=#{!result.nil?}"
54
69
  result
70
+ rescue StandardError => e
71
+ handle_exception(e, level: :warn, handled: false, operation: :cache_local_fetch, key: key, ttl: ttl)
72
+ raise
55
73
  end
56
74
 
57
75
  def delete(key)
58
76
  result = @driver.delete(key)
59
- Legion::Logging.debug "[cache:local] DELETE #{key} success=#{result}" if defined?(Legion::Logging)
77
+ log.debug "[cache:local] DELETE #{key} success=#{result}"
60
78
  result
79
+ rescue StandardError => e
80
+ handle_exception(e, level: :warn, handled: false, operation: :cache_local_delete, key: key)
81
+ raise
61
82
  end
62
83
 
63
84
  def flush(delay = 0)
64
85
  result = @driver.flush(delay)
65
- Legion::Logging.debug '[cache:local] FLUSH completed' if defined?(Legion::Logging)
86
+ log.debug '[cache:local] FLUSH completed'
66
87
  result
88
+ rescue StandardError => e
89
+ handle_exception(e, level: :warn, handled: false, operation: :cache_local_flush, delay: delay)
90
+ raise
67
91
  end
68
92
 
69
93
  def client
@@ -72,13 +96,19 @@ module Legion
72
96
 
73
97
  def close
74
98
  @driver&.close
99
+ @driver = nil
100
+ @driver_name = nil
75
101
  @connected = false
102
+ log.info 'Legion::Cache::Local pool closed'
103
+ @connected
76
104
  end
77
105
 
78
106
  def restart(**opts)
79
107
  settings = local_settings
80
- @driver&.restart(**settings.merge(opts))
108
+ @driver&.restart(**settings.merge(opts, logger: log))
81
109
  @connected = true
110
+ log.info 'Legion::Cache::Local pool restarted'
111
+ @connected
82
112
  end
83
113
 
84
114
  def size
@@ -99,7 +129,10 @@ module Legion
99
129
 
100
130
  def reset!
101
131
  @driver = nil
132
+ @driver_name = nil
102
133
  @connected = false
134
+ log.debug 'Legion::Cache::Local state reset'
135
+ @connected
103
136
  end
104
137
 
105
138
  private
@@ -2,6 +2,7 @@
2
2
 
3
3
  require 'openssl'
4
4
  require 'dalli'
5
+ require 'legion/logging/helper'
5
6
  require 'legion/cache/pool'
6
7
 
7
8
  module Legion
@@ -9,12 +10,14 @@ module Legion
9
10
  module Memcached
10
11
  include Legion::Cache::Pool
11
12
  extend self
13
+ extend Legion::Logging::Helper
12
14
 
13
- def client(server: nil, servers: nil, **opts)
15
+ def client(server: nil, servers: nil, logger: nil, **opts)
14
16
  return @client unless @client.nil?
15
17
 
16
18
  settings = defined?(Legion::Settings) ? Legion::Settings[:cache] : {}
17
19
  servers ||= settings[:servers] || []
20
+ @component_logger = logger || log
18
21
 
19
22
  @pool_size = opts.key?(:pool_size) ? opts[:pool_size] : settings[:pool_size] || 10
20
23
  @timeout = opts.key?(:timeout) ? opts[:timeout] : settings[:timeout] || 5
@@ -23,7 +26,7 @@ module Legion
23
26
  driver: 'memcached', server: server, servers: Array(servers)
24
27
  )
25
28
 
26
- Dalli.logger = Legion::Logging
29
+ Dalli.logger = shared_dalli_logger
27
30
  cache_opts = settings.merge(opts)
28
31
  cache_opts[:value_max_bytes] ||= 8 * 1024 * 1024
29
32
  cache_opts[:serializer] ||= Legion::JSON
@@ -36,40 +39,103 @@ module Legion
36
39
  end
37
40
 
38
41
  @connected = true
39
- Legion::Logging.info "Memcached connected to #{resolved.join(', ')}" if defined?(Legion::Logging)
42
+ cache_logger.info "Memcached connected to #{resolved.join(', ')}"
40
43
  @client
44
+ rescue StandardError => e
45
+ handle_exception(e, level: :error, handled: false, operation: :memcached_client,
46
+ server: server, servers: Array(servers))
47
+ @connected = false
48
+ raise
41
49
  end
42
50
 
43
51
  def get(key)
44
52
  result = client.with { |conn| conn.get(key) }
45
- Legion::Logging.debug "[cache] GET #{key} hit=#{!result.nil?}"
53
+ cache_logger.debug "[cache] GET #{key} hit=#{!result.nil?}"
46
54
  result
55
+ rescue StandardError => e
56
+ handle_exception(e, level: :warn, handled: false, operation: :memcached_get, key: key)
57
+ raise
47
58
  end
48
59
 
49
- def fetch(key, ttl = nil)
50
- result = client.with { |conn| conn.fetch(key, ttl) }
51
- Legion::Logging.debug "[cache] FETCH #{key} hit=#{!result.nil?}"
60
+ def fetch(key, ttl = nil, &)
61
+ result = client.with do |conn|
62
+ if block_given?
63
+ conn.fetch(key, ttl, &)
64
+ else
65
+ conn.fetch(key, ttl)
66
+ end
67
+ end
68
+ cache_logger.debug "[cache] FETCH #{key} hit=#{!result.nil?}"
52
69
  result
70
+ rescue StandardError => e
71
+ handle_exception(e, level: :warn, handled: false, operation: :memcached_fetch, key: key, ttl: ttl)
72
+ raise
53
73
  end
54
74
 
55
75
  def set(key, value, ttl = 180)
56
76
  result = client.with { |conn| conn.set(key, value, ttl).positive? }
57
- Legion::Logging.debug "[cache] SET #{key} ttl=#{ttl} success=#{result} value_class=#{value.class}"
77
+ cache_logger.debug "[cache] SET #{key} ttl=#{ttl} success=#{result} value_class=#{value.class}"
58
78
  result
79
+ rescue StandardError => e
80
+ handle_exception(e, level: :warn, handled: false, operation: :memcached_set, key: key, ttl: ttl)
81
+ raise
59
82
  end
60
83
 
61
84
  def delete(key)
62
85
  result = client.with { |conn| conn.delete(key) == true }
63
- Legion::Logging.debug "[cache] DELETE #{key} success=#{result}"
86
+ cache_logger.debug "[cache] DELETE #{key} success=#{result}"
64
87
  result
88
+ rescue StandardError => e
89
+ handle_exception(e, level: :warn, handled: false, operation: :memcached_delete, key: key)
90
+ raise
65
91
  end
66
92
 
67
93
  def flush(delay = 0)
68
- client.with { |conn| conn.flush(delay).first }
94
+ result = client.with { |conn| conn.flush(delay).first }
95
+ cache_logger.debug '[cache] FLUSH completed'
96
+ result
97
+ rescue StandardError => e
98
+ handle_exception(e, level: :warn, handled: false, operation: :memcached_flush, delay: delay)
99
+ raise
100
+ end
101
+
102
+ def mget(*keys)
103
+ keys = keys.flatten
104
+ return {} if keys.empty?
105
+
106
+ result = client.with { |conn| conn.get_multi(*keys) }
107
+ cache_logger.debug "[cache] MGET keys=#{keys.size} hits=#{result.size}"
108
+ result
109
+ rescue StandardError => e
110
+ handle_exception(e, level: :warn, handled: false, operation: :memcached_mget, key_count: keys.size)
111
+ raise
112
+ end
113
+
114
+ def mset(hash)
115
+ return true if hash.empty?
116
+
117
+ client.with { |conn| conn.set_multi(hash) }
118
+ cache_logger.debug "[cache] MSET keys=#{hash.size}"
119
+ true
120
+ rescue StandardError => e
121
+ handle_exception(e, level: :warn, handled: false, operation: :memcached_mset, key_count: hash.size)
122
+ raise
69
123
  end
70
124
 
71
125
  private
72
126
 
127
+ def cache_logger
128
+ @component_logger || log
129
+ end
130
+
131
+ def shared_dalli_logger
132
+ if defined?(Legion::Cache) && Legion::Cache.respond_to?(:log)
133
+ Legion::Cache.log
134
+ else
135
+ cache_logger
136
+ end
137
+ end
138
+
73
139
  def memcached_tls_context(port:)
74
140
  return nil unless defined?(Legion::Crypt::TLS)
75
141
 
@@ -87,7 +153,7 @@ module Legion
87
153
 
88
154
  Legion::Settings[:cache][:tls] || {}
89
155
  rescue StandardError => e
90
- Legion::Logging.debug("Memcached#memcached_tls_settings failed: #{e.message}") if defined?(Legion::Logging)
156
+ handle_exception(e, level: :warn, handled: true, operation: :memcached_tls_settings)
91
157
  {}
92
158
  end
93
159
  end
@@ -1,9 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'legion/logging/helper'
4
+
3
5
  module Legion
4
6
  module Cache
5
7
  module Memory
6
8
  extend self
9
+ extend Legion::Logging::Helper
7
10
 
8
11
  @store = {}
9
12
  @expiry = {}
@@ -12,6 +15,8 @@ module Legion
12
15
 
13
16
  def setup(**)
14
17
  @connected = true
18
+ log.info 'Legion::Cache::Memory connected'
19
+ @connected
15
20
  end
16
21
 
17
22
  def client(**) = self
@@ -23,14 +28,21 @@ module Legion
23
28
  def get(key)
24
29
  @mutex.synchronize do
25
30
  expire_if_needed(key)
26
- @store[key]
31
+ result = @store[key]
32
+ log.debug { "[cache:memory] GET #{key} hit=#{!result.nil?}" }
33
+ result
27
34
  end
28
35
  end
29
36
 
30
37
  def set(key, value, ttl = nil)
31
38
  @mutex.synchronize do
32
39
  @store[key] = value
33
- @expiry[key] = Time.now + ttl if ttl&.positive?
40
+ if ttl&.positive?
41
+ @expiry[key] = Time.now + ttl
42
+ else
43
+ @expiry.delete(key)
44
+ end
45
+ log.debug { "[cache:memory] SET #{key} ttl=#{ttl.inspect}" }
34
46
  value
35
47
  end
36
48
  end
@@ -39,6 +51,7 @@ module Legion
39
51
  val = get(key)
40
52
  return val unless val.nil?
41
53
 
54
+ log.debug { "[cache:memory] FETCH #{key} miss=true" }
42
55
  val = yield if block_given?
43
56
  set(key, val, ttl)
44
57
  val
@@ -46,16 +59,20 @@ module Legion
46
59
 
47
60
  def delete(key)
48
61
  @mutex.synchronize do
49
- @store.delete(key)
62
+ removed = @store.delete(key)
50
63
  @expiry.delete(key)
64
+ log.debug { "[cache:memory] DELETE #{key} success=#{!removed.nil?}" }
65
+ removed
51
66
  end
52
67
  end
53
68
 
54
69
  def flush(_delay = 0)
55
- @mutex.synchronize do
70
+ result = @mutex.synchronize do
56
71
  @store.clear
57
72
  @expiry.clear
58
73
  end
74
+ log.info 'Legion::Cache::Memory flushed'
75
+ result
59
76
  end
60
77
 
61
78
  def close = nil
@@ -63,14 +80,18 @@ module Legion
63
80
  def shutdown
64
81
  flush
65
82
  @connected = false
83
+ log.info 'Legion::Cache::Memory shut down'
84
+ @connected
66
85
  end
67
86
 
68
87
  def reset!
69
- @mutex.synchronize do
88
+ result = @mutex.synchronize do
70
89
  @store.clear
71
90
  @expiry.clear
72
91
  @connected = false
73
92
  end
93
+ log.info 'Legion::Cache::Memory state reset'
94
+ result
74
95
  end
75
96
 
76
97
  def size = 1
@@ -83,6 +104,7 @@ module Legion
83
104
 
84
105
  @store.delete(key)
85
106
  @expiry.delete(key)
107
+ log.debug { "[cache:memory] EXPIRE #{key}" }
86
108
  end
87
109
  end
88
110
  end