cache_stache 0.2.0 → 0.2.1
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/CHANGELOG.md +34 -0
- data/LICENSE.txt +21 -0
- data/lib/cache_stache/cache_client.rb +9 -5
- data/lib/cache_stache/configuration.rb +13 -5
- data/lib/cache_stache/version.rb +1 -1
- data/spec/unit/cache_client_spec.rb +22 -0
- data/spec/unit/configuration_spec.rb +14 -0
- metadata +3 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 3b3e76904376faf81f690f9b8fd24d63c368295e9c133304b3c16bf0f6e48c6d
|
|
4
|
+
data.tar.gz: 3b23acace11232c359d8d9185946fcb595315ce89e4eacd5b9386de8290e9e71
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 0ed34798119cada11fbbf64f51a61a291e725288dba4fd4bc82353a1feca9adfbf3f654c1070c7664b3e4397f0d2f48cb6ca504cb4963d2a62d7af639fd68c16
|
|
7
|
+
data.tar.gz: 49d081eec0e40ae8d2dddb6159aef9b5524d369770d7826981b0e6a2da2c3cae90c50e6ae34ce7b263f76487ea6aa59a51d55a788c2884caa4f7a35108a685ef
|
data/CHANGELOG.md
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [0.2.1]
|
|
9
|
+
|
|
10
|
+
### Fixed
|
|
11
|
+
|
|
12
|
+
- Fixed Redis calls when `bucket_seconds` or `retention_seconds` are configured with `ActiveSupport::Duration` values
|
|
13
|
+
|
|
14
|
+
## [0.2.0]
|
|
15
|
+
|
|
16
|
+
### Changed
|
|
17
|
+
|
|
18
|
+
- **Breaking:** Replaced `redis_url` config option with `redis`, which accepts a Proc, String URL, or Redis-compatible object
|
|
19
|
+
|
|
20
|
+
## [0.1.1]
|
|
21
|
+
|
|
22
|
+
- Fixed Rails dependency to be >=, not ~>
|
|
23
|
+
|
|
24
|
+
## [0.1.0]
|
|
25
|
+
|
|
26
|
+
### Added
|
|
27
|
+
|
|
28
|
+
- Initial release
|
|
29
|
+
- Cache hit/miss rate tracking via Rails instrumentation
|
|
30
|
+
- Redis-backed statistics storage
|
|
31
|
+
- Dashboard UI for viewing cache metrics
|
|
32
|
+
- Keyspace breakdown view
|
|
33
|
+
- Configurable time windows (minute, hour, day)
|
|
34
|
+
- Rake tasks for cache statistics
|
data/LICENSE.txt
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Nate Berkopec
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
|
13
|
+
all copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
21
|
+
THE SOFTWARE.
|
|
@@ -39,7 +39,7 @@ module CacheStache
|
|
|
39
39
|
redis.eval(
|
|
40
40
|
INCR_AND_EXPIRE_SCRIPT,
|
|
41
41
|
keys: [key],
|
|
42
|
-
argv: [
|
|
42
|
+
argv: [retention_seconds, increments.to_json]
|
|
43
43
|
)
|
|
44
44
|
end
|
|
45
45
|
end
|
|
@@ -79,16 +79,16 @@ module CacheStache
|
|
|
79
79
|
def store_config_metadata
|
|
80
80
|
key = "cache_stache:v1:#{@config.rails_env}:config"
|
|
81
81
|
metadata = {
|
|
82
|
-
bucket_seconds: @config.bucket_seconds,
|
|
83
|
-
retention_seconds:
|
|
82
|
+
bucket_seconds: @config.bucket_seconds.to_i,
|
|
83
|
+
retention_seconds: retention_seconds,
|
|
84
84
|
updated_at: Time.current.to_i
|
|
85
85
|
}
|
|
86
86
|
|
|
87
87
|
without_instrumentation do
|
|
88
88
|
@pool.with do |redis|
|
|
89
89
|
# Use SETEX for atomic set-with-expiry (single command)
|
|
90
|
-
Rails.logger.debug { "CacheStache: Redis SETEX #{key} #{
|
|
91
|
-
redis.setex(key,
|
|
90
|
+
Rails.logger.debug { "CacheStache: Redis SETEX #{key} #{retention_seconds}" }
|
|
91
|
+
redis.setex(key, retention_seconds, metadata.to_json)
|
|
92
92
|
end
|
|
93
93
|
end
|
|
94
94
|
rescue => e
|
|
@@ -164,6 +164,10 @@ module CacheStache
|
|
|
164
164
|
end
|
|
165
165
|
end
|
|
166
166
|
|
|
167
|
+
def retention_seconds
|
|
168
|
+
@config.retention_seconds.to_i
|
|
169
|
+
end
|
|
170
|
+
|
|
167
171
|
def bucket_key(timestamp)
|
|
168
172
|
"cache_stache:v1:#{@config.rails_env}:#{timestamp}"
|
|
169
173
|
end
|
|
@@ -7,13 +7,13 @@ module CacheStache
|
|
|
7
7
|
class Configuration
|
|
8
8
|
DEFAULT_REDIS_OPTIONS = {reconnect_attempts: 0}.freeze
|
|
9
9
|
|
|
10
|
-
attr_accessor :
|
|
11
|
-
:
|
|
12
|
-
attr_reader :keyspaces
|
|
10
|
+
attr_accessor :sample_rate, :enabled, :redis, :redis_pool_size,
|
|
11
|
+
:use_rack_after_reply, :max_buckets
|
|
12
|
+
attr_reader :bucket_seconds, :retention_seconds, :keyspaces
|
|
13
13
|
|
|
14
14
|
def initialize
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
self.bucket_seconds = 5.minutes
|
|
16
|
+
self.retention_seconds = 7.days
|
|
17
17
|
@sample_rate = 1.0
|
|
18
18
|
@enabled = rails_env != "test"
|
|
19
19
|
@use_rack_after_reply = false
|
|
@@ -33,6 +33,14 @@ module CacheStache
|
|
|
33
33
|
# :redis String -> Redis.new(url: redis)
|
|
34
34
|
# :redis Object -> redis (assumed to be a Redis-compatible client)
|
|
35
35
|
#
|
|
36
|
+
def bucket_seconds=(value)
|
|
37
|
+
@bucket_seconds = value.to_i
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def retention_seconds=(value)
|
|
41
|
+
@retention_seconds = value.to_i
|
|
42
|
+
end
|
|
43
|
+
|
|
36
44
|
def build_redis
|
|
37
45
|
case redis
|
|
38
46
|
when Proc
|
data/lib/cache_stache/version.rb
CHANGED
|
@@ -75,6 +75,17 @@ RSpec.describe CacheStache::CacheClient do
|
|
|
75
75
|
expect(ttl).to be <= config.retention_seconds
|
|
76
76
|
end
|
|
77
77
|
|
|
78
|
+
it "increments stats when retention is configured with ActiveSupport::Duration" do
|
|
79
|
+
duration_config = build_test_config(retention_seconds: 7.days)
|
|
80
|
+
duration_client = described_class.new(duration_config)
|
|
81
|
+
|
|
82
|
+
duration_client.increment_stats(bucket_ts, increments)
|
|
83
|
+
|
|
84
|
+
buckets = duration_client.fetch_buckets(bucket_ts - 100, bucket_ts + 100)
|
|
85
|
+
expect(buckets.size).to eq(1)
|
|
86
|
+
expect(buckets.first[:stats]["overall:hits"]).to eq(1.0)
|
|
87
|
+
end
|
|
88
|
+
|
|
78
89
|
it "handles errors gracefully" do
|
|
79
90
|
# Create client, then make the pool raise errors
|
|
80
91
|
test_client = described_class.new(config)
|
|
@@ -168,6 +179,17 @@ RSpec.describe CacheStache::CacheClient do
|
|
|
168
179
|
expect(metadata["updated_at"]).to be_a(Integer)
|
|
169
180
|
end
|
|
170
181
|
|
|
182
|
+
it "stores configuration metadata when durations use ActiveSupport::Duration" do
|
|
183
|
+
duration_config = build_test_config(bucket_seconds: 5.minutes, retention_seconds: 7.days)
|
|
184
|
+
duration_client = described_class.new(duration_config)
|
|
185
|
+
|
|
186
|
+
duration_client.store_config_metadata
|
|
187
|
+
metadata = duration_client.fetch_config_metadata
|
|
188
|
+
|
|
189
|
+
expect(metadata["bucket_seconds"]).to eq(5.minutes.to_i)
|
|
190
|
+
expect(metadata["retention_seconds"]).to eq(7.days.to_i)
|
|
191
|
+
end
|
|
192
|
+
|
|
171
193
|
it "handles errors gracefully" do
|
|
172
194
|
# Create client, then make the pool raise errors
|
|
173
195
|
test_client = described_class.new(config)
|
|
@@ -24,6 +24,20 @@ RSpec.describe CacheStache::Configuration do
|
|
|
24
24
|
it { expect(config.keyspaces).to eq([]) }
|
|
25
25
|
end
|
|
26
26
|
|
|
27
|
+
describe "duration settings" do
|
|
28
|
+
it "coerces bucket_seconds to integer seconds" do
|
|
29
|
+
config.bucket_seconds = 5.minutes
|
|
30
|
+
|
|
31
|
+
expect(config.bucket_seconds).to eq(300)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
it "coerces retention_seconds to integer seconds" do
|
|
35
|
+
config.retention_seconds = 7.days
|
|
36
|
+
|
|
37
|
+
expect(config.retention_seconds).to eq(604_800)
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
27
41
|
describe "#build_redis" do
|
|
28
42
|
it "calls the proc when redis is a Proc" do
|
|
29
43
|
redis_instance = instance_double(Redis)
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: cache_stache
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.2.
|
|
4
|
+
version: 0.2.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- CacheStache contributors
|
|
@@ -155,6 +155,8 @@ executables: []
|
|
|
155
155
|
extensions: []
|
|
156
156
|
extra_rdoc_files: []
|
|
157
157
|
files:
|
|
158
|
+
- CHANGELOG.md
|
|
159
|
+
- LICENSE.txt
|
|
158
160
|
- README.md
|
|
159
161
|
- app/assets/stylesheets/cache_stache/application.css
|
|
160
162
|
- app/assets/stylesheets/cache_stache/pico.css
|