magick-feature-flags 0.9.18 → 0.9.20
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/lib/magick/adapters/memory.rb +6 -2
- data/lib/magick/feature.rb +42 -58
- data/lib/magick/version.rb +1 -1
- data/lib/magick.rb +3 -1
- 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: e4f9379b630e9db00b28614f347d523edb33d63c842d6b5c9fd747be02f1d75d
|
|
4
|
+
data.tar.gz: ffa32ee13faa08781c68870813c15ea7b3dcc15fe65f8c1f2618952251fe870c
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 0f2651c1f8528b4eb385f82a629c7891e0a78ec4a796b574baa8228a2bfcaddf88ee6855af45f9fba9c12b4d7d475e1d8aa6ba6b1002706a1247a8ef81b540e4
|
|
7
|
+
data.tar.gz: 418cc8c6909969581b147df052c72ffc9635a86b07726f69f0c6085bef3bbb804515d34a3d6ca782f8b4c03d4127722a5547a483ca2d0cddfc56f3bef4e6e864
|
|
@@ -11,12 +11,16 @@ module Magick
|
|
|
11
11
|
end
|
|
12
12
|
|
|
13
13
|
def get(feature_name, key)
|
|
14
|
+
# Fast path: avoid mutex if possible (use string keys directly)
|
|
15
|
+
feature_name_str = feature_name.is_a?(String) ? feature_name : feature_name.to_s
|
|
16
|
+
key_str = key.is_a?(String) ? key : key.to_s
|
|
17
|
+
|
|
14
18
|
mutex.synchronize do
|
|
15
19
|
cleanup_expired
|
|
16
|
-
feature_data = store[
|
|
20
|
+
feature_data = store[feature_name_str]
|
|
17
21
|
return nil unless feature_data
|
|
18
22
|
|
|
19
|
-
value = feature_data[
|
|
23
|
+
value = feature_data[key_str]
|
|
20
24
|
deserialize_value(value)
|
|
21
25
|
end
|
|
22
26
|
end
|
data/lib/magick/feature.rb
CHANGED
|
@@ -22,77 +22,54 @@ module Magick
|
|
|
22
22
|
@dependencies = options[:dependencies] ? Array(options[:dependencies]) : []
|
|
23
23
|
@stored_value_initialized = false # Track if @stored_value has been explicitly set
|
|
24
24
|
|
|
25
|
+
# Performance optimizations: cache expensive checks
|
|
26
|
+
@_targeting_empty = true # Will be updated after load_from_adapter
|
|
27
|
+
@_rails_events_enabled = false # Cache Rails events availability (only enable in dev)
|
|
28
|
+
@_perf_metrics_enabled = false # Cache performance metrics (disabled by default for speed)
|
|
29
|
+
|
|
25
30
|
validate_type!
|
|
26
31
|
validate_default_value!
|
|
27
32
|
load_from_adapter
|
|
33
|
+
# Update targeting empty cache after loading
|
|
34
|
+
@_targeting_empty = @targeting.empty?
|
|
35
|
+
# Cache performance metrics availability (check once, not on every call)
|
|
36
|
+
@_perf_metrics_enabled = Magick.performance_metrics != nil
|
|
28
37
|
# Save description and display_name to adapter if they were provided and not already in adapter
|
|
29
38
|
save_metadata_if_new
|
|
30
39
|
end
|
|
31
40
|
|
|
32
41
|
def enabled?(context = {})
|
|
33
|
-
#
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
result = check_enabled(context)
|
|
37
|
-
|
|
38
|
-
if Magick.performance_metrics
|
|
39
|
-
duration = (Time.now - start_time) * 1000 # milliseconds
|
|
40
|
-
Magick.performance_metrics.record(name, 'enabled?', duration, success: true)
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
# Rails 8+ events for enabled/disabled
|
|
44
|
-
if defined?(Magick::Rails::Events) && Magick::Rails::Events.rails8?
|
|
45
|
-
if result
|
|
46
|
-
Magick::Rails::Events.feature_enabled(name, context: context)
|
|
47
|
-
else
|
|
48
|
-
Magick::Rails::Events.feature_disabled(name, context: context)
|
|
49
|
-
end
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
# Warn if deprecated
|
|
53
|
-
if status == :deprecated && result && !context[:allow_deprecated]
|
|
54
|
-
warn "DEPRECATED: Feature '#{name}' is deprecated and will be removed." if Magick.warn_on_deprecated
|
|
55
|
-
|
|
56
|
-
# Rails 8+ event for deprecation warning
|
|
57
|
-
if defined?(Magick::Rails::Events) && Magick::Rails::Events.rails8?
|
|
58
|
-
Magick::Rails::Events.deprecated_warning(name)
|
|
59
|
-
end
|
|
60
|
-
end
|
|
61
|
-
|
|
62
|
-
result
|
|
42
|
+
# Fastest path: check enabled status directly (no overhead)
|
|
43
|
+
check_enabled(context)
|
|
63
44
|
rescue StandardError => e
|
|
64
|
-
if Magick.performance_metrics
|
|
65
|
-
duration = (Time.now - start_time) * 1000
|
|
66
|
-
Magick.performance_metrics.record(name, 'enabled?', duration, success: false)
|
|
67
|
-
end
|
|
68
45
|
# Return false on any error (fail-safe)
|
|
69
46
|
warn "Magick: Error checking feature '#{name}': #{e.message}" if defined?(Rails) && Rails.env.development?
|
|
70
47
|
false
|
|
71
48
|
end
|
|
72
49
|
|
|
73
50
|
def check_enabled(context = {})
|
|
51
|
+
# Fast path: check status first
|
|
74
52
|
return false if status == :inactive
|
|
75
53
|
return false if status == :deprecated && !context[:allow_deprecated]
|
|
76
54
|
|
|
77
|
-
#
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
# Check date/time range targeting
|
|
83
|
-
return false if targeting[:date_range] && !date_range_active?(targeting[:date_range])
|
|
55
|
+
# Fast path: skip targeting checks if targeting is empty (most common case)
|
|
56
|
+
unless @_targeting_empty
|
|
57
|
+
# Check date/time range targeting
|
|
58
|
+
return false if targeting[:date_range] && !date_range_active?(targeting[:date_range])
|
|
84
59
|
|
|
85
|
-
|
|
86
|
-
|
|
60
|
+
# Check IP address targeting
|
|
61
|
+
return false if targeting[:ip_address] && context[:ip_address] && !ip_address_matches?(context[:ip_address])
|
|
87
62
|
|
|
88
|
-
|
|
89
|
-
|
|
63
|
+
# Check custom attributes
|
|
64
|
+
return false if targeting[:custom_attributes] && !custom_attributes_match?(context,
|
|
65
|
+
targeting[:custom_attributes])
|
|
90
66
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
67
|
+
# Check complex conditions
|
|
68
|
+
return false if targeting[:complex_conditions] && !complex_conditions_match?(context,
|
|
69
|
+
targeting[:complex_conditions])
|
|
94
70
|
end
|
|
95
71
|
|
|
72
|
+
# Get value and check based on type
|
|
96
73
|
value = get_value(context)
|
|
97
74
|
case type
|
|
98
75
|
when :boolean
|
|
@@ -131,19 +108,21 @@ module Magick
|
|
|
131
108
|
end
|
|
132
109
|
|
|
133
110
|
def get_value(context = {})
|
|
134
|
-
#
|
|
135
|
-
|
|
136
|
-
|
|
111
|
+
# Fast path: check targeting rules first (only if targeting exists)
|
|
112
|
+
unless @_targeting_empty
|
|
113
|
+
targeting_result = check_targeting(context)
|
|
114
|
+
return targeting_result unless targeting_result.nil?
|
|
115
|
+
end
|
|
137
116
|
|
|
138
|
-
#
|
|
139
|
-
|
|
140
|
-
# We track this by checking if @stored_value_initialized flag is set
|
|
141
|
-
return @stored_value if defined?(@stored_value_initialized) && @stored_value_initialized
|
|
117
|
+
# Fast path: use cached value if initialized (avoid adapter calls)
|
|
118
|
+
return @stored_value if @stored_value_initialized
|
|
142
119
|
|
|
143
120
|
# Load from adapter if instance variable hasn't been initialized
|
|
144
121
|
loaded_value = load_value_from_adapter
|
|
145
122
|
if loaded_value.nil?
|
|
146
|
-
# Value not found in adapter, use default
|
|
123
|
+
# Value not found in adapter, use default and cache it
|
|
124
|
+
@stored_value = default_value
|
|
125
|
+
@stored_value_initialized = true
|
|
147
126
|
default_value
|
|
148
127
|
else
|
|
149
128
|
# Value found in adapter, use it and mark as initialized
|
|
@@ -827,9 +806,14 @@ module Magick
|
|
|
827
806
|
adapter_registry.set(name, 'targeting', targeting)
|
|
828
807
|
|
|
829
808
|
# Update the feature in Magick.features if it's registered
|
|
830
|
-
|
|
809
|
+
if Magick.features.key?(name)
|
|
810
|
+
Magick.features[name].instance_variable_set(:@targeting, targeting.dup)
|
|
811
|
+
# Update targeting empty cache for performance
|
|
812
|
+
Magick.features[name].instance_variable_set(:@_targeting_empty, targeting.empty?)
|
|
813
|
+
end
|
|
831
814
|
|
|
832
|
-
|
|
815
|
+
# Update local targeting empty cache for performance
|
|
816
|
+
@_targeting_empty = targeting.empty?
|
|
833
817
|
|
|
834
818
|
# Explicitly trigger cache invalidation for targeting updates
|
|
835
819
|
# Targeting changes affect enabled? checks, so we need immediate cache invalidation
|
data/lib/magick/version.rb
CHANGED
data/lib/magick.rb
CHANGED
|
@@ -103,7 +103,9 @@ module Magick
|
|
|
103
103
|
end
|
|
104
104
|
|
|
105
105
|
def enabled?(feature_name, context = {})
|
|
106
|
-
|
|
106
|
+
# Fast path: use string key directly (avoid repeated to_s conversion)
|
|
107
|
+
feature_name_str = feature_name.to_s
|
|
108
|
+
feature = features[feature_name_str] || self[feature_name]
|
|
107
109
|
feature.enabled?(context)
|
|
108
110
|
end
|
|
109
111
|
|