cache_stache 0.1.1 → 0.2.0
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/README.md +4 -4
- data/lib/cache_stache/cache_client.rb +1 -1
- data/lib/cache_stache/configuration.rb +32 -3
- data/lib/cache_stache/version.rb +1 -1
- data/lib/generators/cache_stache/templates/cache_stache.rb +9 -3
- data/spec/cache_stache_helper.rb +2 -2
- data/spec/unit/configuration_spec.rb +47 -5
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: d75f242cecde072c5db6fe680a47fcb3b98165a4d12cf46738d64b0c0956c7ef
|
|
4
|
+
data.tar.gz: 86c3c5b676cb94ea1427cbed332f8fc97b2dac235ce22c031511a8ad1014d8b8
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: a4997e8c87c2cb1b974eeac87489b5ad6344adef9dd632d0c1f80429f4aae49edbe76ca4b70557d201a309575f8369a9f361207556c7bb6758630adf6240d174
|
|
7
|
+
data.tar.gz: 623d1edd5b5a304e7839133d9bc4ae9fc9d8f1d67ec76d893df77c6ff506e6c5322b37c657eac5f42d9cbe617f689def250b4974f150f0a0d668348f00766709
|
data/README.md
CHANGED
|
@@ -63,9 +63,9 @@ All settings go in `config/initializers/cache_stache.rb`:
|
|
|
63
63
|
|
|
64
64
|
```ruby
|
|
65
65
|
CacheStache.configure do |config|
|
|
66
|
-
# Redis connection for storing cache metrics
|
|
67
|
-
#
|
|
68
|
-
config.
|
|
66
|
+
# Redis connection for storing cache metrics.
|
|
67
|
+
# Can be a String (URL), Proc, or Redis-compatible object.
|
|
68
|
+
config.redis = ENV.fetch("CACHE_STACHE_REDIS_URL", ENV["REDIS_URL"])
|
|
69
69
|
|
|
70
70
|
# Time bucket size
|
|
71
71
|
config.bucket_seconds = 5.minutes
|
|
@@ -99,7 +99,7 @@ end
|
|
|
99
99
|
|
|
100
100
|
| Setting | Default | What it does |
|
|
101
101
|
|---------|---------|--------------|
|
|
102
|
-
| `
|
|
102
|
+
| `redis` | `ENV["CACHE_STACHE_REDIS_URL"]` or `ENV["REDIS_URL"]` | Redis connection (String URL, Proc, or Redis object) |
|
|
103
103
|
| `redis_pool_size` | 5 | Size of the Redis connection pool |
|
|
104
104
|
| `bucket_seconds` | 5 minutes | Size of each time bucket |
|
|
105
105
|
| `retention_seconds` | 7 days | How long to keep data |
|
|
@@ -5,8 +5,10 @@ require "active_support/core_ext/numeric/time"
|
|
|
5
5
|
|
|
6
6
|
module CacheStache
|
|
7
7
|
class Configuration
|
|
8
|
+
DEFAULT_REDIS_OPTIONS = {reconnect_attempts: 0}.freeze
|
|
9
|
+
|
|
8
10
|
attr_accessor :bucket_seconds, :retention_seconds, :sample_rate, :enabled,
|
|
9
|
-
:
|
|
11
|
+
:redis, :redis_pool_size, :use_rack_after_reply, :max_buckets
|
|
10
12
|
attr_reader :keyspaces
|
|
11
13
|
|
|
12
14
|
def initialize
|
|
@@ -15,13 +17,33 @@ module CacheStache
|
|
|
15
17
|
@sample_rate = 1.0
|
|
16
18
|
@enabled = rails_env != "test"
|
|
17
19
|
@use_rack_after_reply = false
|
|
18
|
-
@
|
|
20
|
+
@redis = ENV.fetch("CACHE_STACHE_REDIS_URL") { ENV.fetch("REDIS_URL", "redis://localhost:6379/0") }
|
|
19
21
|
@redis_pool_size = 5
|
|
20
22
|
@max_buckets = 288
|
|
21
23
|
@keyspaces = []
|
|
22
24
|
@keyspace_cache = {}
|
|
23
25
|
end
|
|
24
26
|
|
|
27
|
+
# Factory method to create a new Redis instance.
|
|
28
|
+
#
|
|
29
|
+
# Handles three options:
|
|
30
|
+
#
|
|
31
|
+
# Option Class Result
|
|
32
|
+
# :redis Proc -> redis.call
|
|
33
|
+
# :redis String -> Redis.new(url: redis)
|
|
34
|
+
# :redis Object -> redis (assumed to be a Redis-compatible client)
|
|
35
|
+
#
|
|
36
|
+
def build_redis
|
|
37
|
+
case redis
|
|
38
|
+
when Proc
|
|
39
|
+
redis.call
|
|
40
|
+
when String
|
|
41
|
+
::Redis.new(DEFAULT_REDIS_OPTIONS.merge(url: redis))
|
|
42
|
+
else
|
|
43
|
+
redis
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
25
47
|
def keyspace(name, &block)
|
|
26
48
|
ks = Keyspace.new(name)
|
|
27
49
|
builder = KeyspaceBuilder.new(ks)
|
|
@@ -43,8 +65,9 @@ module CacheStache
|
|
|
43
65
|
def validate!
|
|
44
66
|
raise Error, "bucket_seconds must be positive" unless bucket_seconds.to_i.positive?
|
|
45
67
|
raise Error, "retention_seconds must be positive" unless retention_seconds.to_i.positive?
|
|
68
|
+
raise Error, "redis must be configured" if redis.nil?
|
|
69
|
+
raise Error, "redis must be a Proc, String (URL), or Redis-compatible object" unless valid_redis_option?
|
|
46
70
|
raise Error, "redis_pool_size must be positive" unless redis_pool_size.to_i.positive?
|
|
47
|
-
raise Error, "redis_url must be configured" if redis_url.to_s.strip.empty?
|
|
48
71
|
raise Error, "sample_rate must be between 0 and 1" unless sample_rate&.between?(0, 1)
|
|
49
72
|
raise Error, "max_buckets must be positive" unless max_buckets.to_i.positive?
|
|
50
73
|
|
|
@@ -64,6 +87,12 @@ module CacheStache
|
|
|
64
87
|
|
|
65
88
|
private
|
|
66
89
|
|
|
90
|
+
def valid_redis_option?
|
|
91
|
+
return true if redis.is_a?(Proc)
|
|
92
|
+
return redis.to_s.strip.length > 0 if redis.is_a?(String)
|
|
93
|
+
true # Assume other objects are Redis-compatible clients
|
|
94
|
+
end
|
|
95
|
+
|
|
67
96
|
def key_digest(key)
|
|
68
97
|
# Use last 4 chars of a simple hash as cache key
|
|
69
98
|
Digest::MD5.hexdigest(key.to_s)[-4..]
|
data/lib/cache_stache/version.rb
CHANGED
|
@@ -4,9 +4,15 @@
|
|
|
4
4
|
# This file configures the CacheStache cache hit rate monitoring system.
|
|
5
5
|
|
|
6
6
|
CacheStache.configure do |config|
|
|
7
|
-
# Redis connection for storing cache metrics
|
|
8
|
-
#
|
|
9
|
-
|
|
7
|
+
# Redis connection for storing cache metrics.
|
|
8
|
+
# Can be a String (URL), Proc, or Redis-compatible object.
|
|
9
|
+
#
|
|
10
|
+
# Examples:
|
|
11
|
+
# config.redis = "redis://localhost:6379/0"
|
|
12
|
+
# config.redis = -> { Redis.new(url: ENV["REDIS_URL"]) }
|
|
13
|
+
# config.redis = ConnectionPool.new { Redis.new }
|
|
14
|
+
#
|
|
15
|
+
config.redis = ENV.fetch("CACHE_STACHE_REDIS_URL", ENV["REDIS_URL"])
|
|
10
16
|
|
|
11
17
|
# Size of time buckets for aggregation (default: 5 minutes)
|
|
12
18
|
config.bucket_seconds = 5.minutes
|
data/spec/cache_stache_helper.rb
CHANGED
|
@@ -50,7 +50,7 @@ module CacheStacheTestHelpers
|
|
|
50
50
|
# Build a test configuration with common defaults
|
|
51
51
|
def build_test_config(keyspaces: {}, **options)
|
|
52
52
|
CacheStache::Configuration.new.tap do |c|
|
|
53
|
-
c.
|
|
53
|
+
c.redis = CACHE_STACHE_TEST_REDIS_URL
|
|
54
54
|
c.bucket_seconds = options.fetch(:bucket_seconds, 300)
|
|
55
55
|
c.retention_seconds = options.fetch(:retention_seconds, 3600)
|
|
56
56
|
c.sample_rate = options.fetch(:sample_rate, 1.0)
|
|
@@ -87,7 +87,7 @@ RSpec.configure do |config|
|
|
|
87
87
|
config.before do
|
|
88
88
|
# Configure CacheStache to use test Redis
|
|
89
89
|
CacheStache.configure do |c|
|
|
90
|
-
c.
|
|
90
|
+
c.redis = CACHE_STACHE_TEST_REDIS_URL
|
|
91
91
|
c.redis_pool_size = 1
|
|
92
92
|
c.enabled = true
|
|
93
93
|
end
|
|
@@ -19,11 +19,38 @@ RSpec.describe CacheStache::Configuration do
|
|
|
19
19
|
it { expect(config.sample_rate).to eq(1.0) }
|
|
20
20
|
it { expect(config.enabled).to be(true) }
|
|
21
21
|
it { expect(config.use_rack_after_reply).to be(false) }
|
|
22
|
-
it { expect(config.
|
|
22
|
+
it { expect(config.redis).to eq(default_redis_url) }
|
|
23
23
|
it { expect(config.redis_pool_size).to eq(5) }
|
|
24
24
|
it { expect(config.keyspaces).to eq([]) }
|
|
25
25
|
end
|
|
26
26
|
|
|
27
|
+
describe "#build_redis" do
|
|
28
|
+
it "calls the proc when redis is a Proc" do
|
|
29
|
+
redis_instance = instance_double(Redis)
|
|
30
|
+
config.redis = -> { redis_instance }
|
|
31
|
+
|
|
32
|
+
expect(config.build_redis).to eq(redis_instance)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
it "creates a Redis instance when redis is a String URL" do
|
|
36
|
+
config.redis = "redis://localhost:6379/1"
|
|
37
|
+
|
|
38
|
+
expect(Redis).to receive(:new).with(
|
|
39
|
+
hash_including(url: "redis://localhost:6379/1")
|
|
40
|
+
).and_call_original
|
|
41
|
+
|
|
42
|
+
result = config.build_redis
|
|
43
|
+
expect(result).to be_a(Redis)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
it "returns the object directly when redis is an Object" do
|
|
47
|
+
redis_instance = instance_double(Redis)
|
|
48
|
+
config.redis = redis_instance
|
|
49
|
+
|
|
50
|
+
expect(config.build_redis).to eq(redis_instance)
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
27
54
|
describe "#keyspace" do
|
|
28
55
|
it "adds a keyspace with the given name" do
|
|
29
56
|
config.keyspace(:views) do
|
|
@@ -135,12 +162,27 @@ RSpec.describe CacheStache::Configuration do
|
|
|
135
162
|
|
|
136
163
|
describe "#validate!" do
|
|
137
164
|
before do
|
|
138
|
-
config.
|
|
165
|
+
config.redis = "redis://localhost:6379/0"
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
it "requires redis" do
|
|
169
|
+
config.redis = nil
|
|
170
|
+
expect { config.validate! }.to raise_error(CacheStache::Error, /redis must be configured/)
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
it "rejects empty string for redis" do
|
|
174
|
+
config.redis = " "
|
|
175
|
+
expect { config.validate! }.to raise_error(CacheStache::Error, /redis must be a Proc, String/)
|
|
139
176
|
end
|
|
140
177
|
|
|
141
|
-
it "
|
|
142
|
-
config.
|
|
143
|
-
expect { config.validate! }.
|
|
178
|
+
it "accepts a Proc for redis" do
|
|
179
|
+
config.redis = -> { Redis.new }
|
|
180
|
+
expect { config.validate! }.not_to raise_error
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
it "accepts an Object for redis" do
|
|
184
|
+
config.redis = instance_double(Redis)
|
|
185
|
+
expect { config.validate! }.not_to raise_error
|
|
144
186
|
end
|
|
145
187
|
|
|
146
188
|
it "requires redis_pool_size to be positive" do
|