legion-cache 1.3.1 → 1.3.2
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 +4 -4
- data/.gitignore +1 -0
- data/CHANGELOG.md +10 -0
- data/README.md +28 -1
- data/lib/legion/cache/cacheable.rb +123 -0
- data/lib/legion/cache/version.rb +1 -1
- data/lib/legion/cache.rb +1 -0
- metadata +2 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: '0295f21258e4a7d824099be9c2c12a7c594d0db3e72dd8d5b5f823bb332e6869'
|
|
4
|
+
data.tar.gz: 5e581fc50c7bb13e52e9a38ae99a085af836ae21ec6d126d3a0d1fc6c79ad5aa
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: dc08f391040cab62c39795bd1d477f7d8e47ba4b5ffe3e88856957b829876d37ae06e15a48ff5469652e3c3574d5da529bccb7f00e9df162caadcc4d50fd93e1
|
|
7
|
+
data.tar.gz: 67717d9fd58c0669e319f0b0de94dee0d8178f17d78ba3fac2afc142660e26668b6700ccbb370b88274f1295d7ab534627768f981f3e1c4f98f9aa5ac86ae3db
|
data/.gitignore
CHANGED
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [1.3.2] - 2026-03-20
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
- `Legion::Cache::Cacheable` module for transparent method-level caching
|
|
7
|
+
- `cache_method` DSL: declare cached methods with TTL, scope, and key exclusions
|
|
8
|
+
- `build_cache_key`: deterministic MD5-based cache keys from module path + method + filtered args
|
|
9
|
+
- `bypass_local_method_cache:` kwarg for force-refresh on cached methods
|
|
10
|
+
- In-memory fallback store with TTL expiry when no cache backend is available
|
|
11
|
+
- `memory_clear!` class method for test isolation
|
|
12
|
+
|
|
3
13
|
## [1.3.1] - 2026-03-20
|
|
4
14
|
|
|
5
15
|
### Added
|
data/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Caching wrapper for the [LegionIO](https://github.com/LegionIO/LegionIO) framework. Provides a consistent interface for Memcached (via `dalli`) and Redis (via `redis` gem) with connection pooling. Driver selection is config-driven.
|
|
4
4
|
|
|
5
|
-
**Version**: 1.3.
|
|
5
|
+
**Version**: 1.3.2
|
|
6
6
|
|
|
7
7
|
## Installation
|
|
8
8
|
|
|
@@ -117,6 +117,33 @@ Both `server` (singular string) and `servers` (array) are accepted and merged. D
|
|
|
117
117
|
|
|
118
118
|
Override via `Legion::Settings[:cache_local]`.
|
|
119
119
|
|
|
120
|
+
## Method Caching
|
|
121
|
+
|
|
122
|
+
Runner modules can use `cache_method` to transparently cache method results with TTL:
|
|
123
|
+
|
|
124
|
+
```ruby
|
|
125
|
+
module Runners::Presence
|
|
126
|
+
extend Legion::Cache::Cacheable
|
|
127
|
+
|
|
128
|
+
cache_method :get_presence, ttl: 300, exclude_from_key: [:token]
|
|
129
|
+
|
|
130
|
+
def get_presence(user_id: 'me', **)
|
|
131
|
+
conn = graph_connection(**)
|
|
132
|
+
response = conn.get("#{user_path(user_id)}/presence")
|
|
133
|
+
{ availability: response.body['availability'], activity: response.body['activity'] }
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
Every caller of `get_presence` gets cached results for 5 minutes. Use `bypass_local_method_cache: true` to force-refresh:
|
|
139
|
+
|
|
140
|
+
```ruby
|
|
141
|
+
runner.get_presence(user_id: 'me') # cached
|
|
142
|
+
runner.get_presence(user_id: 'me', bypass_local_method_cache: true) # fresh
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
Options: `ttl:` (seconds), `scope:` (`:local` or `:global`), `exclude_from_key:` (args to ignore in cache key). Falls back to in-memory store when no cache backend is available.
|
|
146
|
+
|
|
120
147
|
## Pool API
|
|
121
148
|
|
|
122
149
|
```ruby
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'digest'
|
|
4
|
+
|
|
5
|
+
module Legion
|
|
6
|
+
module Cache
|
|
7
|
+
module Cacheable
|
|
8
|
+
def self.extended(base)
|
|
9
|
+
base.instance_variable_set(:@cached_methods, {})
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def cached_methods
|
|
13
|
+
@cached_methods ||= {}
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def cache_method(method_name, ttl:, scope: :local, exclude_from_key: [])
|
|
17
|
+
exclude_from_key |= %i[token bypass_local_method_cache]
|
|
18
|
+
cached_methods[method_name] = { ttl: ttl, scope: scope, exclude_from_key: exclude_from_key }
|
|
19
|
+
|
|
20
|
+
mod_name = name || 'Anonymous'
|
|
21
|
+
config = cached_methods[method_name]
|
|
22
|
+
|
|
23
|
+
wrapper = Module.new do
|
|
24
|
+
define_method(method_name) do |bypass_local_method_cache: false, **kwargs|
|
|
25
|
+
key = Legion::Cache::Cacheable.build_cache_key(
|
|
26
|
+
mod_name, method_name, exclude: config[:exclude_from_key], **kwargs
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
unless bypass_local_method_cache
|
|
30
|
+
cached = Legion::Cache::Cacheable.cache_read(key, scope: config[:scope])
|
|
31
|
+
return cached unless cached.nil?
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
result = super(**kwargs)
|
|
35
|
+
Legion::Cache::Cacheable.cache_write(key, result, ttl: config[:ttl], scope: config[:scope])
|
|
36
|
+
result
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
prepend wrapper
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def self.build_cache_key(mod_name, method_name, exclude:, **kwargs)
|
|
44
|
+
filtered = kwargs.except(*exclude)
|
|
45
|
+
args_hash = Digest::MD5.hexdigest(filtered.sort.to_s)
|
|
46
|
+
"#{mod_name}.#{method_name}.#{args_hash}"
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def self.cache_read(key, scope:)
|
|
50
|
+
case scope
|
|
51
|
+
when :global
|
|
52
|
+
return Legion::Cache.get(key) if global_cache_available?
|
|
53
|
+
|
|
54
|
+
memory_read(key)
|
|
55
|
+
else
|
|
56
|
+
local_cache_read(key) || memory_read(key)
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def self.cache_write(key, value, ttl:, scope:)
|
|
61
|
+
case scope
|
|
62
|
+
when :global
|
|
63
|
+
if global_cache_available?
|
|
64
|
+
Legion::Cache.set(key, value, ttl)
|
|
65
|
+
else
|
|
66
|
+
memory_write(key, value, ttl)
|
|
67
|
+
end
|
|
68
|
+
else
|
|
69
|
+
if local_cache_available?
|
|
70
|
+
local_cache_write(key, value, ttl)
|
|
71
|
+
else
|
|
72
|
+
memory_write(key, value, ttl)
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def self.global_cache_available?
|
|
78
|
+
defined?(Legion::Cache) && Legion::Cache.respond_to?(:connected?) && Legion::Cache.connected?
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def self.local_cache_available?
|
|
82
|
+
defined?(Legion::Cache::Local) && Legion::Cache::Local.respond_to?(:connected?) && Legion::Cache::Local.connected?
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def self.local_cache_read(key)
|
|
86
|
+
return nil unless local_cache_available?
|
|
87
|
+
|
|
88
|
+
Legion::Cache::Local.get(key)
|
|
89
|
+
rescue StandardError
|
|
90
|
+
nil
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def self.local_cache_write(key, value, ttl)
|
|
94
|
+
return unless local_cache_available?
|
|
95
|
+
|
|
96
|
+
Legion::Cache::Local.set(key, value, ttl)
|
|
97
|
+
rescue StandardError
|
|
98
|
+
nil
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
# In-memory fallback store (class-level, process-wide)
|
|
102
|
+
def self.memory_store
|
|
103
|
+
@memory_store ||= {}
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def self.memory_read(key)
|
|
107
|
+
entry = memory_store[key]
|
|
108
|
+
return nil unless entry
|
|
109
|
+
return nil if Time.now.utc > entry[:expires_at]
|
|
110
|
+
|
|
111
|
+
entry[:value]
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def self.memory_write(key, value, ttl)
|
|
115
|
+
memory_store[key] = { value: value, expires_at: Time.now.utc + ttl }
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
def self.memory_clear!
|
|
119
|
+
@memory_store = {}
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
end
|
data/lib/legion/cache/version.rb
CHANGED
data/lib/legion/cache.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: legion-cache
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.3.
|
|
4
|
+
version: 1.3.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Esity
|
|
@@ -100,6 +100,7 @@ files:
|
|
|
100
100
|
- README.md
|
|
101
101
|
- legion-cache.gemspec
|
|
102
102
|
- lib/legion/cache.rb
|
|
103
|
+
- lib/legion/cache/cacheable.rb
|
|
103
104
|
- lib/legion/cache/local.rb
|
|
104
105
|
- lib/legion/cache/memcached.rb
|
|
105
106
|
- lib/legion/cache/pool.rb
|