magick-feature-flags 0.9.10 → 0.9.18

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: 6ff57666debab09c055a1709e27902b4ff03780b62ca97382e3f0df191b4b1ce
4
- data.tar.gz: 1420d03c05427c4c0ef7f319debb108542b36fa5fccf999ad13e3bd0571c0451
3
+ metadata.gz: 7df3e59dc8f0736e18fb93603f53038f48b5302769c42cc37ab87f2afcba0307
4
+ data.tar.gz: e0235e0c7518860061b7b67a27aee9c1be88346c8292733aae0a2c794c2288d7
5
5
  SHA512:
6
- metadata.gz: 2150805b902ed92fc1f033493e47697541078d21fb7d9d1e827ddf8b22d9e17fd58e8e1ed926aa47fecf1662c491d910ecba528a0d1ce8f306b340c9e0b35a16
7
- data.tar.gz: 21144c7b0ad4c6c23eb379f088898757f438058dc9c2278f3fc30a03e188b03a6b58e9cb4aac8d5e37127523b5bcfc562a00c08079de95da035d10b9afa28ad5
6
+ metadata.gz: 0a76c637a3cd96cebd6fa91be4f10df8e1174713fabb82c4cdb8df1cecd2d4c6c6ea46e00949cc485e6c0a3d46a9180c718204361a2630c8a71a069a0c6f6bbd
7
+ data.tar.gz: f0682f004002eab91412ee9d948e69f3f84de41238ab2d5ca3f06abec1abf2616c86063a66198f8a596f32d8dc2cf545c9db0b62961e6dc98a4d97a39b01e5cc
data/lib/magick/config.rb CHANGED
@@ -41,21 +41,50 @@ module Magick
41
41
  def redis(url: nil, namespace: nil, **options)
42
42
  @redis_url = url if url
43
43
  @redis_namespace = namespace if namespace
44
- configure_redis_adapter(url: url, namespace: namespace, **options)
44
+ redis_adapter = configure_redis_adapter(url: url, namespace: namespace, **options)
45
+
46
+ # Automatically create Registry adapter if it doesn't exist
47
+ # This allows users to just call `redis url: ...` without needing to call `adapter :registry`
48
+ if @adapter_registry
49
+ # If registry already exists, update it with the new Redis adapter
50
+ # This allows reconfiguring Redis without recreating the registry
51
+ if redis_adapter && @adapter_registry.is_a?(Adapters::Registry)
52
+ # Update the Redis adapter in the existing registry
53
+ @adapter_registry.instance_variable_set(:@redis_adapter, redis_adapter)
54
+ # Restart cache invalidation subscriber with new Redis adapter
55
+ @adapter_registry.send(:start_cache_invalidation_subscriber) if redis_adapter
56
+ end
57
+ else
58
+ memory_adapter = configure_memory_adapter
59
+ cb = Magick::CircuitBreaker.new(
60
+ failure_threshold: @circuit_breaker_threshold,
61
+ timeout: @circuit_breaker_timeout
62
+ )
63
+ @adapter_registry = Adapters::Registry.new(
64
+ memory_adapter,
65
+ redis_adapter,
66
+ circuit_breaker: cb,
67
+ async: @async_updates
68
+ )
69
+ end
70
+
71
+ redis_adapter
45
72
  end
46
73
 
47
74
  def performance_metrics(enabled: true, redis_tracking: nil, batch_size: 100, flush_interval: 60, **_options)
48
75
  return unless enabled
49
76
 
50
- @performance_metrics = PerformanceMetrics.new(batch_size: batch_size, flush_interval: flush_interval)
51
- # Store redis_tracking preference for later application
77
+ # Store redis_tracking preference before creating instance
52
78
  @performance_metrics_redis_tracking = redis_tracking
53
- # Enable Redis tracking if explicitly set to true, otherwise defer to apply! method
54
- if redis_tracking == true
55
- @performance_metrics.enable_redis_tracking(enable: true)
56
- elsif redis_tracking == false
57
- @performance_metrics.enable_redis_tracking(enable: false)
58
- end
79
+ # Create instance with redis_enabled set if explicitly provided
80
+ initial_redis_enabled = redis_tracking == true
81
+ @performance_metrics = PerformanceMetrics.new(
82
+ batch_size: batch_size,
83
+ flush_interval: flush_interval,
84
+ redis_enabled: initial_redis_enabled
85
+ )
86
+ # If explicitly set to false, disable it
87
+ @performance_metrics.enable_redis_tracking(enable: false) if redis_tracking == false
59
88
  # If nil, will be auto-determined in apply! method
60
89
  @performance_metrics
61
90
  end
@@ -100,10 +129,19 @@ module Magick
100
129
  Magick.performance_metrics = performance_metrics
101
130
  # Re-apply redis_tracking setting after assignment (in case object was replaced)
102
131
  if defined?(@performance_metrics_redis_tracking) && !@performance_metrics_redis_tracking.nil?
132
+ # Explicitly set value takes precedence
103
133
  Magick.performance_metrics.enable_redis_tracking(enable: @performance_metrics_redis_tracking)
104
134
  # Otherwise, auto-enable if Redis adapter is configured
105
135
  # Check Magick.adapter_registry (after it's been set) instead of local instance variable
106
136
  elsif Magick.adapter_registry.is_a?(Adapters::Registry) && Magick.adapter_registry.redis_available?
137
+ # Always enable if Redis adapter is available (unless explicitly disabled above)
138
+ Magick.performance_metrics.enable_redis_tracking(enable: true)
139
+ end
140
+ elsif Magick.performance_metrics
141
+ # If no new performance_metrics was configured, but one exists, still try to enable Redis tracking
142
+ # if Redis adapter is available and redis_tracking wasn't explicitly disabled
143
+ # Only auto-enable if not explicitly disabled
144
+ if Magick.adapter_registry.is_a?(Adapters::Registry) && Magick.adapter_registry.redis_available? && !(defined?(@performance_metrics_redis_tracking) && @performance_metrics_redis_tracking == false)
107
145
  Magick.performance_metrics.enable_redis_tracking(enable: true)
108
146
  end
109
147
  end
@@ -150,7 +188,7 @@ module Magick
150
188
  memory_adapter = memory || configure_memory_adapter
151
189
  redis_adapter = redis || configure_redis_adapter
152
190
 
153
- cb = circuit_breaker || CircuitBreaker.new(
191
+ cb = circuit_breaker || Magick::CircuitBreaker.new(
154
192
  failure_threshold: @circuit_breaker_threshold,
155
193
  timeout: @circuit_breaker_timeout
156
194
  )
@@ -24,17 +24,23 @@ module Magick
24
24
  end
25
25
  end
26
26
 
27
- def initialize(batch_size: 100, flush_interval: 60)
27
+ def initialize(batch_size: 100, flush_interval: 60, redis_enabled: nil)
28
28
  @metrics = []
29
29
  @mutex = Mutex.new
30
- @usage_count = Hash.new(0)
31
- @pending_updates = Hash.new(0) # For Redis batching
30
+ @usage_count = Hash.new(0) # Memory-only counts (reset on each process boot)
31
+ @pending_updates = Hash.new(0) # For Redis batching (reset on each process boot)
32
+ @flushed_counts = Hash.new(0) # Track counts that have been flushed to Redis (to avoid double-counting)
32
33
  @batch_size = batch_size
33
34
  @flush_interval = flush_interval
34
35
  @last_flush = Time.now
35
- @redis_enabled = false
36
+ # If redis_enabled is explicitly set, use it; otherwise default to false
37
+ # It will be enabled later via enable_redis_tracking if Redis adapter is available
38
+ @redis_enabled = redis_enabled.nil? ? false : redis_enabled
36
39
  end
37
40
 
41
+ # Public accessor for redis_enabled
42
+ attr_reader :redis_enabled
43
+
38
44
  def record(feature_name, operation, duration, success: true)
39
45
  feature_name_str = feature_name.to_s
40
46
  metric = Metric.new(feature_name_str, operation, duration, success: success)
@@ -43,7 +49,8 @@ module Magick
43
49
  @metrics << metric
44
50
  @usage_count[feature_name_str] += 1
45
51
  @pending_updates[feature_name_str] += 1
46
- # Keep only last 1000 metrics
52
+ # Keep only last 1000 metrics (as a safety limit)
53
+ # Note: Metrics are removed from memory after flushing to Redis to reduce memory usage
47
54
  @metrics.shift if @metrics.length > 1000
48
55
  end
49
56
 
@@ -59,41 +66,98 @@ module Magick
59
66
  end
60
67
 
61
68
  def flush_to_redis_if_needed
62
- return unless @redis_enabled
69
+ # Always try to flush if Redis adapter is available, even if @redis_enabled is false
70
+ # This ensures stats are collected even if redis_enabled wasn't set correctly
71
+ adapter = Magick.adapter_registry || Magick.default_adapter_registry
72
+ return unless adapter # No adapter at all, skip
73
+
74
+ redis_available = adapter.is_a?(Magick::Adapters::Registry) && adapter.redis_available?
75
+
76
+ return unless redis_available || @redis_enabled
63
77
  return if @pending_updates.empty?
64
78
 
65
79
  should_flush = false
66
80
  @mutex.synchronize do
67
- # Flush if we have enough pending updates or enough time has passed
68
- should_flush = true if @pending_updates.size >= @batch_size || (Time.now - @last_flush) >= @flush_interval
81
+ # Flush if we have enough pending updates (sum of all counts) or enough time has passed
82
+ # Check total count of pending updates, not just number of keys
83
+ total_pending_count = @pending_updates.values.sum
84
+ should_flush = true if total_pending_count >= @batch_size || (Time.now - @last_flush) >= @flush_interval
69
85
  end
70
86
 
71
87
  flush_to_redis if should_flush
72
88
  end
73
89
 
90
+ # Force flush pending updates to Redis immediately
91
+ # Useful when you need up-to-date stats across processes
92
+ def force_flush_to_redis
93
+ return if @pending_updates.empty?
94
+
95
+ flush_to_redis
96
+ end
97
+
74
98
  def flush_to_redis
75
99
  updates_to_flush = nil
100
+ duration_stats_to_flush = {}
76
101
  @mutex.synchronize do
77
102
  return if @pending_updates.empty?
78
103
 
79
104
  updates_to_flush = @pending_updates.dup
105
+ flushed_feature_names = updates_to_flush.keys.to_set
80
106
  @pending_updates.clear
107
+ # Track what we're flushing so we don't double-count in usage_count
108
+ updates_to_flush.each do |feature_name, count|
109
+ @flushed_counts[feature_name] += count
110
+ end
111
+
112
+ # Collect duration stats for flushed features
113
+ # Group metrics by feature_name and operation, sum durations and count occurrences
114
+ @metrics.each do |metric|
115
+ next unless flushed_feature_names.include?(metric.feature_name) && metric.success
116
+
117
+ key = "#{metric.feature_name}:#{metric.operation}"
118
+ duration_stats_to_flush[key] ||= { sum: 0.0, count: 0, feature_name: metric.feature_name,
119
+ operation: metric.operation }
120
+ duration_stats_to_flush[key][:sum] += metric.duration
121
+ duration_stats_to_flush[key][:count] += 1
122
+ end
123
+
124
+ # Remove metrics for flushed features from memory to reduce memory usage
125
+ # Metrics are already persisted in Redis, so we don't need to keep them in memory
126
+ @metrics.reject! { |m| flushed_feature_names.include?(m.feature_name) }
127
+
81
128
  @last_flush = Time.now
82
129
  end
83
130
 
84
131
  return if updates_to_flush.nil? || updates_to_flush.empty?
85
132
 
86
133
  # Update Redis in batch
134
+ # Always try to flush if Redis adapter is available, regardless of @redis_enabled flag
135
+ # This ensures stats are collected even if redis_enabled wasn't set correctly
87
136
  begin
88
137
  adapter = Magick.adapter_registry || Magick.default_adapter_registry
89
138
  if adapter.is_a?(Magick::Adapters::Registry) && adapter.redis_available?
90
139
  redis = adapter.redis_client
91
140
  if redis
141
+ # Flush usage counts
92
142
  updates_to_flush.each do |feature_name, count|
93
143
  redis_key = "magick:stats:#{feature_name}"
94
144
  redis.incrby(redis_key, count)
95
145
  redis.expire(redis_key, 86_400 * 7) # Keep stats for 7 days
96
146
  end
147
+
148
+ # Flush duration stats (sum and count for calculating averages)
149
+ duration_stats_to_flush.each do |_key, stats|
150
+ sum_key = "magick:duration:sum:#{stats[:feature_name]}:#{stats[:operation]}"
151
+ count_key = "magick:duration:count:#{stats[:feature_name]}:#{stats[:operation]}"
152
+ redis.incrbyfloat(sum_key, stats[:sum])
153
+ redis.incrby(count_key, stats[:count])
154
+ redis.expire(sum_key, 86_400 * 7) # Keep stats for 7 days
155
+ redis.expire(count_key, 86_400 * 7)
156
+ end
157
+
158
+ # Auto-enable redis tracking if we successfully flushed to Redis
159
+ # This ensures redis_enabled is set correctly even if config didn't work
160
+ @redis_enabled ||= true
97
161
  end
98
162
  end
99
163
  rescue StandardError => e
@@ -103,67 +167,137 @@ module Magick
103
167
  end
104
168
 
105
169
  def enable_redis_tracking(enable: true)
170
+ old_value = @redis_enabled
106
171
  @redis_enabled = enable
172
+
107
173
  # Flush any pending updates when enabling
108
- flush_to_redis if enable && !@pending_updates.empty?
174
+ if enable && !@pending_updates.empty?
175
+ begin
176
+ flush_to_redis
177
+ rescue StandardError => e
178
+ # Don't fail if flush fails - the flag is still set
179
+ if defined?(Rails) && Rails.env.development?
180
+ warn "Magick: Failed to flush stats when enabling Redis tracking: #{e.message}"
181
+ end
182
+ end
183
+ end
184
+
185
+ # Verify the value was set (for debugging)
186
+ if !(@redis_enabled == enable) && defined?(Rails) && Rails.env.development?
187
+ warn "Magick: Failed to set redis_enabled to #{enable}, current value: #{@redis_enabled}"
188
+ end
189
+
190
+ true
109
191
  end
110
192
 
111
193
  def average_duration(feature_name: nil, operation: nil)
194
+ # Calculate from memory metrics (current process, not yet flushed)
112
195
  filtered = @metrics.select do |m|
113
196
  (feature_name.nil? || m.feature_name == feature_name.to_s) &&
114
197
  (operation.nil? || m.operation == operation.to_s) &&
115
198
  m.success
116
199
  end
117
- return 0.0 if filtered.empty?
118
200
 
119
- filtered.sum(&:duration) / filtered.length.to_f
201
+ memory_sum = filtered.sum(&:duration)
202
+ memory_count = filtered.length
203
+
204
+ # Also get from Redis if available (persisted across processes)
205
+ redis_sum = 0.0
206
+ redis_count = 0
207
+ begin
208
+ adapter = Magick.adapter_registry || Magick.default_adapter_registry
209
+ if adapter.is_a?(Magick::Adapters::Registry) && adapter.redis_available?
210
+ redis = adapter.redis_client
211
+ if redis
212
+ if feature_name && operation
213
+ # Specific feature and operation
214
+ sum_key = "magick:duration:sum:#{feature_name}:#{operation}"
215
+ count_key = "magick:duration:count:#{feature_name}:#{operation}"
216
+ redis_sum = redis.get(sum_key).to_f
217
+ redis_count = redis.get(count_key).to_i
218
+ elsif feature_name
219
+ # All operations for this feature
220
+ pattern = "magick:duration:sum:#{feature_name}:*"
221
+ redis.keys(pattern).each do |sum_key|
222
+ op = sum_key.to_s.sub("magick:duration:sum:#{feature_name}:", '')
223
+ count_key = "magick:duration:count:#{feature_name}:#{op}"
224
+ redis_sum += redis.get(sum_key).to_f
225
+ redis_count += redis.get(count_key).to_i
226
+ end
227
+ else
228
+ # All features and operations (not recommended, but supported)
229
+ redis.keys('magick:duration:sum:*').each do |sum_key|
230
+ count_key = sum_key.to_s.sub(':sum:', ':count:')
231
+ redis_sum += redis.get(sum_key).to_f
232
+ redis_count += redis.get(count_key).to_i
233
+ end
234
+ end
235
+ end
236
+ end
237
+ rescue StandardError
238
+ # Silently fail
239
+ end
240
+
241
+ total_sum = memory_sum + redis_sum
242
+ total_count = memory_count + redis_count
243
+
244
+ return 0.0 if total_count == 0
245
+
246
+ total_sum / total_count.to_f
120
247
  end
121
248
 
122
249
  def usage_count(feature_name)
123
250
  feature_name_str = feature_name.to_s
124
- memory_count = @usage_count[feature_name_str] || 0
125
251
 
126
- # Also check Redis if enabled
252
+ # Force flush any pending updates for this feature before reading to ensure accuracy
253
+ # This ensures stats are synced across processes immediately
254
+ force_flush_to_redis if @pending_updates[feature_name_str] && @pending_updates[feature_name_str] > 0
255
+
256
+ # Memory count = total counts in current process minus what we've already flushed
257
+ # This avoids double-counting with Redis
258
+ memory_count = (@usage_count[feature_name_str] || 0) - (@flushed_counts[feature_name_str] || 0)
259
+ memory_count = 0 if memory_count < 0 # Safety check
260
+
261
+ # Redis count = total counts from all processes (including this process's flushed counts)
127
262
  redis_count = 0
128
- if @redis_enabled
129
- begin
130
- adapter = Magick.adapter_registry || Magick.default_adapter_registry
131
- if adapter.is_a?(Magick::Adapters::Registry) && adapter.redis_available?
132
- redis = adapter.redis_client
133
- if redis
134
- redis_key = "magick:stats:#{feature_name_str}"
135
- redis_count = redis.get(redis_key).to_i
136
- end
263
+ begin
264
+ adapter = Magick.adapter_registry || Magick.default_adapter_registry
265
+ if adapter.is_a?(Magick::Adapters::Registry) && adapter.redis_available?
266
+ redis = adapter.redis_client
267
+ if redis
268
+ redis_key = "magick:stats:#{feature_name_str}"
269
+ redis_count = redis.get(redis_key).to_i
137
270
  end
138
- rescue StandardError
139
- # Silently fail
140
271
  end
272
+ rescue StandardError
273
+ # Silently fail
141
274
  end
142
275
 
143
- memory_count + redis_count
276
+ # Total = Redis (all processes, all time) + memory (current process, not yet flushed)
277
+ redis_count + memory_count
144
278
  end
145
279
 
146
280
  def most_used_features(limit: 10)
147
281
  # Combine memory and Redis counts
148
282
  combined_counts = @usage_count.dup
149
283
 
150
- if @redis_enabled
151
- begin
152
- adapter = Magick.adapter_registry || Magick.default_adapter_registry
153
- if adapter.is_a?(Magick::Adapters::Registry) && adapter.redis_available?
154
- redis = adapter.redis_client
155
- if redis
156
- # Get all stats keys
157
- redis.keys('magick:stats:*').each do |key|
158
- feature_name = key.to_s.sub('magick:stats:', '')
159
- redis_count = redis.get(key).to_i
160
- combined_counts[feature_name] = (combined_counts[feature_name] || 0) + redis_count
161
- end
284
+ # Always check Redis if adapter is available (not just if @redis_enabled)
285
+ # This ensures we get the full count even if redis_enabled flag wasn't set correctly
286
+ begin
287
+ adapter = Magick.adapter_registry || Magick.default_adapter_registry
288
+ if adapter.is_a?(Magick::Adapters::Registry) && adapter.redis_available?
289
+ redis = adapter.redis_client
290
+ if redis
291
+ # Get all stats keys
292
+ redis.keys('magick:stats:*').each do |key|
293
+ feature_name = key.to_s.sub('magick:stats:', '')
294
+ redis_count = redis.get(key).to_i
295
+ combined_counts[feature_name] = (combined_counts[feature_name] || 0) + redis_count
162
296
  end
163
297
  end
164
- rescue StandardError
165
- # Silently fail
166
298
  end
299
+ rescue StandardError
300
+ # Silently fail
167
301
  end
168
302
 
169
303
  combined_counts.sort_by { |_name, count| -count }.first(limit).to_h
@@ -174,6 +308,7 @@ module Magick
174
308
  @metrics.clear
175
309
  @usage_count.clear
176
310
  @pending_updates.clear
311
+ @flushed_counts.clear
177
312
  end
178
313
  end
179
314
  end
@@ -29,11 +29,44 @@ if defined?(Rails)
29
29
  memory_adapter = Adapters::Memory.new
30
30
  redis_adapter = Adapters::Redis.new(redis_client)
31
31
  magick.adapter_registry = Adapters::Registry.new(memory_adapter, redis_adapter)
32
- # Re-apply Redis tracking if performance metrics exists
33
- Magick.reapply_redis_tracking! if Magick.performance_metrics
32
+ # Enable Redis tracking if performance metrics exists and Redis is available
33
+ if Magick.performance_metrics && redis_adapter
34
+ Magick.performance_metrics.enable_redis_tracking(enable: true)
35
+ end
34
36
  rescue StandardError => e
35
37
  Rails.logger&.warn "Magick: Failed to initialize Redis adapter: #{e.message}. Using memory-only adapter."
38
+ # Still set up memory adapter even if Redis fails
39
+ memory_adapter = Adapters::Memory.new
40
+ magick.adapter_registry = Adapters::Registry.new(memory_adapter, nil)
36
41
  end
42
+ else
43
+ # No Redis gem, use memory-only adapter
44
+ memory_adapter = Adapters::Memory.new
45
+ magick.adapter_registry = Adapters::Registry.new(memory_adapter, nil)
46
+ end
47
+ end
48
+ end
49
+
50
+ # Ensure adapter_registry is always set (fallback to default if not configured)
51
+ unless Magick.adapter_registry
52
+ Magick.adapter_registry = Magick.default_adapter_registry
53
+ end
54
+
55
+ # Ensure adapter_registry is set and Redis tracking is enabled after all initializers have run
56
+ # This ensures user's config/initializers/magick.rb has been loaded
57
+ config.after_initialize do
58
+ # Ensure adapter_registry is set (fallback to default if not configured)
59
+ unless Magick.adapter_registry
60
+ Magick.adapter_registry = Magick.default_adapter_registry
61
+ end
62
+
63
+ # Force enable Redis tracking if Redis adapter is available
64
+ # This is a final safety net to ensure stats are collected
65
+ if Magick.performance_metrics && Magick.adapter_registry.is_a?(Adapters::Registry) && Magick.adapter_registry.redis_available?
66
+ Magick.performance_metrics.enable_redis_tracking(enable: true)
67
+ # Double-check it was enabled (for debugging)
68
+ unless Magick.performance_metrics.redis_enabled
69
+ Rails.logger&.warn 'Magick: Failed to enable Redis tracking despite Redis adapter being available'
37
70
  end
38
71
  end
39
72
  end
@@ -64,6 +97,12 @@ if defined?(Rails)
64
97
  # Preload features in request store
65
98
  config.to_prepare do
66
99
  RequestStore.store[:magick_features] ||= {} if defined?(RequestStore)
100
+
101
+ # Final check: ensure Redis tracking is enabled (runs on every request in development)
102
+ # This is the absolute last chance to enable it
103
+ if Magick.performance_metrics && Magick.adapter_registry.is_a?(Adapters::Registry) && Magick.adapter_registry.redis_available? && !Magick.performance_metrics.redis_enabled
104
+ Magick.performance_metrics.enable_redis_tracking(enable: true)
105
+ end
67
106
  end
68
107
  end
69
108
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Magick
4
- VERSION = '0.9.10'
4
+ VERSION = '0.9.18'
5
5
  end
data/lib/magick.rb CHANGED
@@ -28,24 +28,63 @@ require_relative 'magick/dsl'
28
28
 
29
29
  module Magick
30
30
  class << self
31
- attr_accessor :adapter_registry, :default_adapter, :performance_metrics, :audit_log, :versioning,
31
+ attr_accessor :adapter_registry, :default_adapter, :audit_log, :versioning,
32
32
  :warn_on_deprecated
33
33
 
34
+ # Override performance_metrics setter to auto-enable Redis tracking
35
+ def performance_metrics=(value)
36
+ @performance_metrics = value
37
+ # Auto-enable Redis tracking if Redis adapter is available
38
+ if value && adapter_registry.is_a?(Adapters::Registry) && adapter_registry.redis_available?
39
+ value.enable_redis_tracking(enable: true)
40
+ end
41
+ value
42
+ end
43
+
44
+ # Override adapter_registry setter to auto-enable Redis tracking on existing performance_metrics
45
+ def adapter_registry=(value)
46
+ @adapter_registry = value
47
+ # Auto-enable Redis tracking if performance_metrics exists and Redis adapter is available
48
+ if performance_metrics && value.is_a?(Adapters::Registry) && value.redis_available?
49
+ performance_metrics.enable_redis_tracking(enable: true)
50
+ end
51
+ value
52
+ end
53
+
54
+ # Getter for performance_metrics
55
+ def performance_metrics
56
+ @performance_metrics
57
+ end
58
+
34
59
  def configure(&block)
35
60
  @performance_metrics ||= PerformanceMetrics.new
36
61
  @audit_log ||= AuditLog.new
37
62
  @warn_on_deprecated ||= false
63
+ # Ensure adapter_registry is set (fallback to default if not configured)
64
+ @adapter_registry ||= default_adapter_registry
38
65
 
39
66
  # Support both old style and new DSL style
40
67
  return unless block_given?
41
68
 
42
69
  if block.arity.zero?
43
- # New DSL style
70
+ # New DSL style - calls apply! automatically
44
71
  ConfigDSL.configure(&block)
45
72
  else
46
- # Old style
73
+ # Old style - need to manually reapply Redis tracking after configuration
47
74
  yield self
75
+ # Ensure adapter_registry is still set after configuration
76
+ @adapter_registry ||= default_adapter_registry
77
+ # Enable Redis tracking if adapter is available and performance_metrics exists
78
+ # Only enable if not already enabled (to avoid overriding explicit false setting)
79
+ if @performance_metrics && @adapter_registry.is_a?(Adapters::Registry) && @adapter_registry.redis_available?
80
+ unless @performance_metrics.instance_variable_get(:@redis_enabled)
81
+ @performance_metrics.enable_redis_tracking(enable: true)
82
+ end
83
+ end
48
84
  end
85
+
86
+ # Final check: ensure adapter_registry is set
87
+ @adapter_registry ||= default_adapter_registry
49
88
  end
50
89
 
51
90
  def [](feature_name)
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: magick-feature-flags
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.10
4
+ version: 0.9.18
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrew Lobanov