ff-ruby-server-sdk 1.4.0 → 1.4.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6411beee7ad512c4e70efc7d9fbd45c71835b18eff4bf41b8e056333074dc083
4
- data.tar.gz: 1f13b504ffda1c95f4956813ec8dc887935340a26dcba09689864250dbf4589b
3
+ metadata.gz: e2bcc6b6312ee2462bbf6a2a689ddee47c6000bc010db561eb72b5204a7c8d8f
4
+ data.tar.gz: 7058cd57f6e72cb2c649b51071eaebed405ff3aac691f4aa186a096da70692b9
5
5
  SHA512:
6
- metadata.gz: f3cc5c07fe09718e260ca6ab19bb720d0db276a60f6ff9b9229a4374bdfeebce0b519e6edbbf82d202183382f55c447d3ed2293b614035ab4f8e2ff7880b4d56
7
- data.tar.gz: 7771ae2a6823afffa73dbda7e49beceab7ad973e8ef4cb8dfdd1781ca0de7ee3a10822d19c58a749a90ffe492c72e5dbcaf0b8a05a04159c510e38d675ff25c9
6
+ metadata.gz: 85ff6d9cda7f5579a7eeedce0f7ea293ccf95ff426b413f53aa09c22a0caa4bc1890607c63d67a0b3c58295d537f830a85e81ae45a2a6afafdd4d0521daa60df
7
+ data.tar.gz: '089aeb5abb536d43e118bade66a80fde7b70e1b74ce1a96fa32d53d7a4a61f08ec7b4c5d35a987e60f11fc4a8791b7233bad01c742bfc4ebc5545a738a13038d'
@@ -46,7 +46,7 @@ The synchronous method is useful for environments where feature flag decisions a
46
46
 
47
47
  You can use the `wait_for_initialization` method, optionally providing a timeout in milliseconds to prevent waiting indefinitely in case of unrecoverable isues, e.g. incorrect API key used.
48
48
 
49
- **Usage with a timeout**
49
+ **Usage without a timeout**
50
50
 
51
51
  ```ruby
52
52
  client = CfClient.instance
@@ -57,13 +57,15 @@ client.wait_for_initialization
57
57
  result = client.bool_variation("bool_flag", target, false)
58
58
  ```
59
59
 
60
- **Usage without a timeout**
60
+ **Usage with a timeout**
61
61
 
62
62
  ```ruby
63
63
  client = CfClient.instance
64
64
  client.init(api_key, config)
65
65
 
66
- client.wait_for_initialization(timeout_ms: 3000)
66
+ # Only wait for 30 seconds, after which if the SDK has not initialized the call will
67
+ # unblock and the SDK will then serve defaults
68
+ client.wait_for_initialization(timeout_ms: 30000)
67
69
 
68
70
  result = client.bool_variation("bool_flag", target, false)
69
71
  ```
@@ -23,7 +23,7 @@ class InnerClientFlagEvaluateCallback < FlagEvaluateCallback
23
23
 
24
24
  def process_evaluation(feature_config, target, variation)
25
25
 
26
- @logger.debug "Processing evaluation: " + feature_config.feature.to_s + ", " + target.identifier.to_s
26
+ @logger.debug "Processing evaluation: #{feature_config&.feature || 'nil feature'}, #{target&.identifier || 'nil target'}"
27
27
 
28
28
  @metrics_processor.register_evaluation(target, feature_config, variation)
29
29
  end
@@ -2,11 +2,12 @@ class MetricsEvent
2
2
 
3
3
  attr_accessor :feature_config, :target, :variation
4
4
 
5
- def initialize(feature_config, target, variation)
5
+ def initialize(feature_config, target, variation, logger)
6
6
 
7
7
  @target = target
8
8
  @variation = variation
9
9
  @feature_config = feature_config
10
+ @logger = logger
10
11
  freeze
11
12
  end
12
13
 
@@ -15,6 +16,15 @@ class MetricsEvent
15
16
  end
16
17
 
17
18
  def eql?(other)
19
+ # Guard clause other is the same type.
20
+ # While it should be, this adds protection for an edge case we are seeing with very large
21
+ # project sizes. Issue being tracked in FFM-12192, and once resolved, can feasibly remove
22
+ # these checks in a future release.
23
+ unless other.is_a?(MetricsEvent)
24
+ @logger.warn("Warning: Attempted to compare MetricsEvent with #{other.class.name}" )
25
+ return false
26
+ end
27
+
18
28
  feature_config.feature == other.feature_config.feature and
19
29
  variation.identifier == other.variation.identifier and
20
30
  target.identifier == other.target.identifier
@@ -9,6 +9,7 @@ require_relative "../api/metrics_event"
9
9
  require_relative "../api/summary_metrics"
10
10
 
11
11
  class MetricsProcessor < Closeable
12
+ GLOBAL_TARGET = Target.new(identifier: "__global__cf_target", name: "Global Target").freeze
12
13
 
13
14
  class FrequencyMap < Concurrent::Map
14
15
  def initialize(options = nil, &block)
@@ -29,6 +30,7 @@ class MetricsProcessor < Closeable
29
30
  self[key]
30
31
  end
31
32
 
33
+ # TODO Will be removed in V2 in favour of simplified clearing. Currently not used outside of tests.
32
34
  def drain_to_map
33
35
  result = {}
34
36
  each_key do |key|
@@ -65,7 +67,6 @@ class MetricsProcessor < Closeable
65
67
  @target_attribute = "target"
66
68
  @global_target_identifier = "__global__cf_target" # <--- This target identifier is used to aggregate and send data for all
67
69
  # targets as a summary
68
- @global_target = Target.new("RubySDK1", identifier = @global_target_identifier, name = @global_target_name)
69
70
  @ready = false
70
71
  @jar_version = Ff::Ruby::Server::Sdk::VERSION
71
72
  @server = "server"
@@ -111,12 +112,34 @@ class MetricsProcessor < Closeable
111
112
 
112
113
  def register_evaluation(target, feature_config, variation)
113
114
  register_evaluation_metric(feature_config, variation)
114
- register_target_metric(target)
115
+ if target
116
+ register_target_metric(target)
117
+ end
115
118
  end
116
119
 
117
120
  private
118
121
 
119
122
  def register_evaluation_metric(feature_config, variation)
123
+ # Guard clause to ensure feature_config, @global_target, and variation are valid.
124
+ # While they should be, this adds protection for an edge case we are seeing with very large
125
+ # project sizes. Issue being tracked in FFM-12192, and once resolved, can feasibly remove
126
+ # these checks in a future release.
127
+ if feature_config.nil? || !feature_config.respond_to?(:feature) || feature_config.feature.nil?
128
+ @config.logger.warn("Skipping invalid MetricsEvent: feature_config is missing or incomplete. feature_config=#{feature_config.inspect}")
129
+ return
130
+ end
131
+
132
+ if GLOBAL_TARGET.nil? || !GLOBAL_TARGET.respond_to?(:identifier) || GLOBAL_TARGET.identifier.nil?
133
+ @config.logger.warn("Skipping invalid MetricsEvent: global_target is missing or incomplete. global_target=#{GLOBAL_TARGET.inspect}")
134
+ return
135
+ end
136
+
137
+ if variation.nil? || !variation.respond_to?(:identifier) || variation.identifier.nil?
138
+ @config.logger.warn("Skipping iInvalid MetricsEvent: variation is missing or incomplete. variation=#{variation.inspect}")
139
+ return
140
+ end
141
+
142
+
120
143
  if @evaluation_metrics.size > @max_buffer_size
121
144
  unless @evaluation_warning_issued.true?
122
145
  SdkCodes.warn_metrics_evaluations_max_size_exceeded(@config.logger)
@@ -125,7 +148,7 @@ class MetricsProcessor < Closeable
125
148
  return
126
149
  end
127
150
 
128
- event = MetricsEvent.new(feature_config, @global_target, variation)
151
+ event = MetricsEvent.new(feature_config, GLOBAL_TARGET, variation, @config.logger)
129
152
  @evaluation_metrics.increment event
130
153
  end
131
154
 
@@ -158,8 +181,14 @@ class MetricsProcessor < Closeable
158
181
  end
159
182
 
160
183
  def send_data_and_reset_cache(evaluation_metrics_map, target_metrics_map)
161
- evaluation_metrics_map_clone = evaluation_metrics_map.drain_to_map
184
+ # Clone and clear evaluation metrics map
185
+ evaluation_metrics_map_clone = Concurrent::Map.new
162
186
 
187
+ evaluation_metrics_map.each_pair do |key, value|
188
+ evaluation_metrics_map_clone[key] = value
189
+ end
190
+
191
+ evaluation_metrics_map.clear
163
192
  target_metrics_map_clone = Concurrent::Map.new
164
193
 
165
194
  target_metrics_map.each_pair do |key, value|
@@ -188,6 +217,24 @@ class MetricsProcessor < Closeable
188
217
 
189
218
  total_count = 0
190
219
  evaluation_metrics_map.each do |key, value|
220
+ # While Components should not be missing, this adds protection for an edge case we are seeing with very large
221
+ # project sizes. Issue being tracked in FFM-12192, and once resolved, can feasibly remove
222
+ # these checks in a future release.
223
+ # Initialize an array to collect missing components
224
+ missing_components = []
225
+
226
+ # Check each required component and add to missing_components if absent
227
+ missing_components << 'feature_config' unless key.respond_to?(:feature_config) && key.feature_config
228
+ missing_components << 'variation' unless key.respond_to?(:variation) && key.variation
229
+ missing_components << 'target' unless key.respond_to?(:target) && key.target
230
+ missing_components << 'count' if value.nil?
231
+
232
+ # If any components are missing, log a detailed warning and skip processing
233
+ unless missing_components.empty?
234
+ @config.logger.warn "Skipping invalid metrics event: missing #{missing_components.join(', ')} in key: #{key.inspect}, full details: #{key.inspect}"
235
+ next
236
+ end
237
+
191
238
  total_count += value
192
239
  metrics_data = OpenapiClient::MetricsData.new({ :attributes => [] })
193
240
  metrics_data.timestamp = (Time.now.to_f * 1000).to_i
@@ -5,7 +5,7 @@ module Ff
5
5
  module Server
6
6
  module Sdk
7
7
 
8
- VERSION = "1.4.0"
8
+ VERSION = "1.4.1"
9
9
  end
10
10
  end
11
11
  end
data/scripts/sdk_specs.sh CHANGED
@@ -1,4 +1,4 @@
1
1
  #!/bin/bash
2
2
 
3
3
  export ff_ruby_sdk="ff-ruby-server-sdk"
4
- export ff_ruby_sdk_version="1.4.0"
4
+ export ff_ruby_sdk_version="1.4.1"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ff-ruby-server-sdk
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.4.0
4
+ version: 1.4.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - 'Miloš Vasić, cyr.: Милош Васић'
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-10-02 00:00:00.000000000 Z
11
+ date: 2024-11-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -305,7 +305,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
305
305
  - !ruby/object:Gem::Version
306
306
  version: '0'
307
307
  requirements: []
308
- rubygems_version: 3.5.16
308
+ rubygems_version: 3.5.22
309
309
  signing_key:
310
310
  specification_version: 4
311
311
  summary: Harness is a feature management platform that helps teams to build better