magick-feature-flags 0.9.23 → 0.9.24
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 +13 -4
- data/lib/magick/config.rb +38 -6
- data/lib/magick/rails/railtie.rb +7 -1
- data/lib/magick/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 9aaecf68655a77ae48f4f7b2d7f760528a4aa14aa5f37b5f8a603897e3040d40
|
|
4
|
+
data.tar.gz: 8b9694162f06fded4597aaadd14334c515f996979161915004ef113a979aba38
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 4f47eaddee984442954a6a9f556c434469f8f9c923c93daa4971e232ff0b8ee248c96a510c505c3caecd99ed38687ec2a27544d8624837030a767b13b6253d0f
|
|
7
|
+
data.tar.gz: e2523e3c4051c6922638bdf6739eb3dc89e92822a1a93b0f542d6827bb5706a59d8de3bf2d56d1125584d5e20c016f92b3314b9f1f6ac047cab0ce828b00ad7d
|
data/README.md
CHANGED
|
@@ -10,7 +10,7 @@ A performant and memory-efficient feature toggle gem for Ruby and Rails applicat
|
|
|
10
10
|
- **Rails Integration**: Seamless integration with Rails, including request store caching
|
|
11
11
|
- **DSL Support**: Define features in a Ruby DSL file (`config/features.rb`)
|
|
12
12
|
- **Thread-Safe**: All operations are thread-safe for concurrent access
|
|
13
|
-
- **Performance**:
|
|
13
|
+
- **Performance**: Lightning-fast feature checks with async metrics recording and memory-first caching strategy
|
|
14
14
|
- **Advanced Features**: Circuit breaker, audit logging, performance metrics, versioning, and more
|
|
15
15
|
|
|
16
16
|
## Installation
|
|
@@ -52,7 +52,8 @@ The generator creates `config/initializers/magick.rb` with sensible defaults. Yo
|
|
|
52
52
|
```ruby
|
|
53
53
|
Magick.configure do
|
|
54
54
|
# Configure Redis (optional)
|
|
55
|
-
|
|
55
|
+
# Use database 1 by default to avoid conflicts with Rails cache (which uses DB 0)
|
|
56
|
+
redis url: ENV['REDIS_URL'], db: 1
|
|
56
57
|
|
|
57
58
|
# Enable features
|
|
58
59
|
performance_metrics enabled: true
|
|
@@ -73,7 +74,10 @@ Magick.configure do
|
|
|
73
74
|
memory_ttl 7200 # 2 hours
|
|
74
75
|
|
|
75
76
|
# Redis configuration
|
|
76
|
-
|
|
77
|
+
# Use separate database (DB 1) to avoid conflicts with Rails cache (DB 0)
|
|
78
|
+
# This ensures feature toggles persist even when Rails cache is cleared
|
|
79
|
+
redis url: ENV['REDIS_URL'], namespace: 'magick:features', db: 1
|
|
80
|
+
# Or include database in URL: redis url: 'redis://localhost:6379/1'
|
|
77
81
|
|
|
78
82
|
# Circuit breaker settings
|
|
79
83
|
circuit_breaker threshold: 5, timeout: 60
|
|
@@ -383,7 +387,9 @@ Magick.configure do
|
|
|
383
387
|
end
|
|
384
388
|
```
|
|
385
389
|
|
|
386
|
-
**
|
|
390
|
+
**Performance:** Metrics are recorded asynchronously in a background thread, ensuring zero overhead on feature checks. The `enabled?` method remains lightning-fast even with metrics enabled.
|
|
391
|
+
|
|
392
|
+
**Note:** When `redis_tracking: true` is set, usage counts are persisted to Redis and aggregated across all processes, giving you total usage statistics. Metrics are automatically flushed in batches to minimize Redis overhead.
|
|
387
393
|
|
|
388
394
|
#### Audit Logging
|
|
389
395
|
|
|
@@ -424,6 +430,9 @@ With Redis configured:
|
|
|
424
430
|
- ✅ Persistent storage across restarts
|
|
425
431
|
- ✅ Zero Redis calls on feature checks (only memory lookups)
|
|
426
432
|
- ✅ Automatic cache invalidation when features change in any process
|
|
433
|
+
- ✅ **Isolated from Rails cache** - Use `db: 1` to store feature toggles in a separate Redis database, ensuring they persist even when Rails cache is cleared
|
|
434
|
+
|
|
435
|
+
**Important:** By default, Magick uses Redis database 1 to avoid conflicts with Rails cache (which typically uses database 0). This ensures that clearing Rails cache (`Rails.cache.clear`) won't affect your feature toggle states.
|
|
427
436
|
|
|
428
437
|
### Feature Types
|
|
429
438
|
|
data/lib/magick/config.rb
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
module Magick
|
|
4
4
|
class Config
|
|
5
5
|
attr_accessor :adapter_registry, :performance_metrics, :audit_log, :versioning, :warn_on_deprecated,
|
|
6
|
-
:async_updates, :memory_ttl, :circuit_breaker_threshold, :circuit_breaker_timeout, :redis_url, :redis_namespace, :environment
|
|
6
|
+
:async_updates, :memory_ttl, :circuit_breaker_threshold, :circuit_breaker_timeout, :redis_url, :redis_namespace, :redis_db, :environment
|
|
7
7
|
|
|
8
8
|
def initialize
|
|
9
9
|
@warn_on_deprecated = false
|
|
@@ -12,6 +12,7 @@ module Magick
|
|
|
12
12
|
@circuit_breaker_threshold = 5
|
|
13
13
|
@circuit_breaker_timeout = 60
|
|
14
14
|
@redis_namespace = 'magick:features'
|
|
15
|
+
@redis_db = nil # Use default database (0) unless specified
|
|
15
16
|
@environment = defined?(Rails) ? Rails.env.to_s : 'development'
|
|
16
17
|
end
|
|
17
18
|
|
|
@@ -38,10 +39,11 @@ module Magick
|
|
|
38
39
|
configure_memory_adapter(**options)
|
|
39
40
|
end
|
|
40
41
|
|
|
41
|
-
def redis(url: nil, namespace: nil, **options)
|
|
42
|
+
def redis(url: nil, namespace: nil, db: nil, **options)
|
|
42
43
|
@redis_url = url if url
|
|
43
44
|
@redis_namespace = namespace if namespace
|
|
44
|
-
|
|
45
|
+
@redis_db = db if db
|
|
46
|
+
redis_adapter = configure_redis_adapter(url: url, namespace: namespace, db: db, **options)
|
|
45
47
|
|
|
46
48
|
# Automatically create Registry adapter if it doesn't exist
|
|
47
49
|
# This allows users to just call `redis url: ...` without needing to call `adapter :registry`
|
|
@@ -161,17 +163,33 @@ module Magick
|
|
|
161
163
|
adapter
|
|
162
164
|
end
|
|
163
165
|
|
|
164
|
-
def configure_redis_adapter(url: nil, namespace: nil, client: nil)
|
|
166
|
+
def configure_redis_adapter(url: nil, namespace: nil, db: nil, client: nil)
|
|
165
167
|
return nil unless defined?(Redis)
|
|
166
168
|
|
|
167
169
|
url ||= @redis_url
|
|
168
170
|
namespace ||= @redis_namespace
|
|
171
|
+
db ||= @redis_db
|
|
169
172
|
|
|
170
173
|
redis_client = client || begin
|
|
174
|
+
redis_options = {}
|
|
175
|
+
|
|
171
176
|
if url
|
|
172
|
-
|
|
177
|
+
# Parse URL to extract database number if present
|
|
178
|
+
parsed_url = URI.parse(url) rescue nil
|
|
179
|
+
db_from_url = nil
|
|
180
|
+
if parsed_url && parsed_url.path && parsed_url.path.length > 1
|
|
181
|
+
# Redis URL format: redis://host:port/db_number
|
|
182
|
+
db_from_url = parsed_url.path[1..-1].to_i
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
# Use db parameter if provided, otherwise use db from URL, otherwise nil (default DB 0)
|
|
186
|
+
final_db = db || db_from_url
|
|
187
|
+
redis_options[:db] = final_db if final_db
|
|
188
|
+
redis_options[:url] = url
|
|
189
|
+
::Redis.new(redis_options)
|
|
173
190
|
else
|
|
174
|
-
|
|
191
|
+
redis_options[:db] = db if db
|
|
192
|
+
::Redis.new(redis_options)
|
|
175
193
|
end
|
|
176
194
|
rescue StandardError
|
|
177
195
|
nil
|
|
@@ -179,6 +197,20 @@ module Magick
|
|
|
179
197
|
|
|
180
198
|
return nil unless redis_client
|
|
181
199
|
|
|
200
|
+
# If db was specified but not in URL, select it explicitly
|
|
201
|
+
# This handles cases where URL doesn't include db number
|
|
202
|
+
if db && url
|
|
203
|
+
parsed_url = URI.parse(url) rescue nil
|
|
204
|
+
url_has_db = parsed_url && parsed_url.path && parsed_url.path.length > 1
|
|
205
|
+
unless url_has_db
|
|
206
|
+
begin
|
|
207
|
+
redis_client.select(db)
|
|
208
|
+
rescue StandardError
|
|
209
|
+
# Ignore if SELECT fails (some Redis setups don't support SELECT, e.g., Redis Cluster)
|
|
210
|
+
end
|
|
211
|
+
end
|
|
212
|
+
end
|
|
213
|
+
|
|
182
214
|
adapter = Adapters::Redis.new(redis_client)
|
|
183
215
|
adapter.instance_variable_set(:@namespace, namespace) if namespace
|
|
184
216
|
adapter
|
data/lib/magick/rails/railtie.rb
CHANGED
|
@@ -25,7 +25,13 @@ if defined?(Rails)
|
|
|
25
25
|
if defined?(Redis)
|
|
26
26
|
begin
|
|
27
27
|
redis_url = app.config.respond_to?(:redis_url) ? app.config.redis_url : nil
|
|
28
|
-
|
|
28
|
+
# Use database 1 for Magick by default to avoid conflicts with Rails cache (which uses DB 0)
|
|
29
|
+
# Users can override this in their config/initializers/magick.rb
|
|
30
|
+
redis_db = 1
|
|
31
|
+
redis_options = {}
|
|
32
|
+
redis_options[:url] = redis_url if redis_url
|
|
33
|
+
redis_options[:db] = redis_db
|
|
34
|
+
redis_client = redis_url ? ::Redis.new(redis_options) : ::Redis.new(db: redis_db)
|
|
29
35
|
memory_adapter = Adapters::Memory.new
|
|
30
36
|
redis_adapter = Adapters::Redis.new(redis_client)
|
|
31
37
|
magick.adapter_registry = Adapters::Registry.new(memory_adapter, redis_adapter)
|
data/lib/magick/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: magick-feature-flags
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.9.
|
|
4
|
+
version: 0.9.24
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Andrew Lobanov
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2025-
|
|
11
|
+
date: 2025-12-02 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: rspec
|