amplitude-experiment 1.2.5 → 1.3.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 39fff5d1285490313a587d9df46b1cf68bb84c5672d9927871ba83b195bbf613
4
- data.tar.gz: 8f26de2e9de3585d5696646cd384841a732e9c0944520b479dc42ab423f5f168
3
+ metadata.gz: 5bebb227696dfbf198819fdba2640a000c67ca3a9c89d593cc03a4433ef532c8
4
+ data.tar.gz: fb79230b6409d82cf3d849f07cb1705abc22ae10a27e7bdfbbe6d1add1e100d0
5
5
  SHA512:
6
- metadata.gz: 96bb141478ceb429381894466cd63fd937ddd8e27d4d5ac4ee4b02ed6bacfef34750f151fbfffbc088fb5562e3ee2aef23e4da9ed8907f591a37a9195fc5e8b9
7
- data.tar.gz: 631d94a409a81132540504f135b56b2b6ccdfb407e9e11f250486ee9cf6d74e481e5a2dc3e23e652ed07b42abde9ffb9d2cbd9f17e1128c4248b1e55e53e2d61
6
+ metadata.gz: bc2885c715208465d15a6b4217e684a2caa0eb055963b1a5ff0fcdc7829239b894d685f305383cd483fff2b082592c395672c1d75140e0537543b5479e425557
7
+ data.tar.gz: 6d1c6b2488ddc5e28d0162e3535be65c3ed3c5767e08af71acdf7933a6f42a20c3d6994638b45713c8f9a9dd20ccfe054a9323465badff1acdd6960fb5cf9376
@@ -15,6 +15,7 @@ require 'experiment/local/assignment/assignment_service'
15
15
  require 'experiment/local/assignment/assignment_config'
16
16
  require 'experiment/util/lru_cache'
17
17
  require 'experiment/util/hash'
18
+ require 'experiment/error'
18
19
 
19
20
  # Amplitude Experiment Module
20
21
  module AmplitudeExperiment
@@ -0,0 +1,11 @@
1
+ module AmplitudeExperiment
2
+ # FetchError
3
+ class FetchError < StandardError
4
+ attr_reader :status_code
5
+
6
+ def initialize(status_code, message)
7
+ super(message)
8
+ @status_code = status_code
9
+ end
10
+ end
11
+ end
@@ -19,24 +19,37 @@ module AmplitudeExperiment
19
19
  else
20
20
  Logger::INFO
21
21
  end
22
- endpoint = "#{@config.server_url}/sdk/vardata"
22
+ endpoint = "#{@config.server_url}/sdk/v2/vardata?v=0"
23
23
  @uri = URI(endpoint)
24
24
  raise ArgumentError, 'Experiment API key is empty' if @api_key.nil? || @api_key.empty?
25
25
  end
26
26
 
27
- # Fetch all variants for a user synchronous.
27
+ # Fetch all variants for a user synchronously.
28
28
  #
29
29
  # This method will automatically retry if configured (default).
30
30
  # @param [User] user
31
31
  # @return [Hash] Variants Hash
32
32
  def fetch(user)
33
+ filter_default_variants(fetch_internal(user))
34
+ rescue StandardError => e
35
+ @logger.error("[Experiment] Failed to fetch variants: #{e.message}")
36
+ {}
37
+ end
38
+
39
+ # Fetch all variants for a user synchronously.
40
+ #
41
+ # This method will automatically retry if configured (default). This function differs from fetch as it will
42
+ # return a default variant object if the flag was evaluated but the user was not assigned (i.e. off).
43
+ # @param [User] user
44
+ # @return [Hash] Variants Hash
45
+ def fetch_v2(user)
33
46
  fetch_internal(user)
34
47
  rescue StandardError => e
35
48
  @logger.error("[Experiment] Failed to fetch variants: #{e.message}")
36
49
  {}
37
50
  end
38
51
 
39
- # Fetch all variants for a user asynchronous.
52
+ # Fetch all variants for a user asynchronously.
40
53
  #
41
54
  # This method will automatically retry if configured (default).
42
55
  # @param [User] user
@@ -53,6 +66,24 @@ module AmplitudeExperiment
53
66
  end
54
67
  end
55
68
 
69
+ # Fetch all variants for a user asynchronously. This function differs from fetch as it will
70
+ # return a default variant object if the flag was evaluated but the user was not assigned (i.e. off).
71
+ #
72
+ # This method will automatically retry if configured (default).
73
+ # @param [User] user
74
+ # @yield [User, Hash] callback block takes user object and variants hash
75
+ def fetch_async_v2(user, &callback)
76
+ Thread.new do
77
+ variants = fetch_internal(user)
78
+ yield(user, filter_default_variants(variants)) unless callback.nil?
79
+ variants
80
+ rescue StandardError => e
81
+ @logger.error("[Experiment] Failed to fetch variants: #{e.message}")
82
+ yield(user, {}) unless callback.nil?
83
+ {}
84
+ end
85
+ end
86
+
56
87
  private
57
88
 
58
89
  # @param [User] user
@@ -61,12 +92,14 @@ module AmplitudeExperiment
61
92
  do_fetch(user, @config.fetch_timeout_millis)
62
93
  rescue StandardError => e
63
94
  @logger.error("[Experiment] Fetch failed: #{e.message}")
64
- begin
65
- return retry_fetch(user)
66
- rescue StandardError => err
67
- @logger.error("[Experiment] Retry Fetch failed: #{err.message}")
95
+ if should_retry_fetch?(e)
96
+ begin
97
+ retry_fetch(user)
98
+ rescue StandardError => err
99
+ @logger.error("[Experiment] Retry Fetch failed: #{err.message}")
100
+ end
68
101
  end
69
- throw e
102
+ raise e
70
103
  end
71
104
 
72
105
  # @param [User] user
@@ -108,6 +141,8 @@ module AmplitudeExperiment
108
141
  end_time = Time.now
109
142
  elapsed = (end_time - start_time) * 1000.0
110
143
  @logger.debug("[Experiment] Fetch complete in #{elapsed.round(3)} ms")
144
+ raise FetchError.new(response.code.to_i, "Fetch error response: status=#{response.code} #{response.message}") if response.code != '200'
145
+
111
146
  json = JSON.parse(response.body)
112
147
  variants = parse_json_variants(json)
113
148
  @logger.debug("[Experiment] Fetched variants: #{variants}")
@@ -128,7 +163,7 @@ module AmplitudeExperiment
128
163
  # value was previously under the "key" field
129
164
  variant_value = value.fetch('key')
130
165
  end
131
- variants.store(key, Variant.new(variant_value, value.fetch('payload', nil)))
166
+ variants.store(key, Variant.new(variant_value, value.fetch('payload', nil), value.fetch('key', nil), value.fetch('metadata', nil)))
132
167
  end
133
168
  variants
134
169
  end
@@ -140,5 +175,24 @@ module AmplitudeExperiment
140
175
  user.library = "experiment-ruby-server/#{VERSION}"
141
176
  user
142
177
  end
178
+
179
+ def should_retry_fetch?(err)
180
+ return err.status_code < 400 || err.status_code >= 500 || err.status_code == 429 if err.is_a?(FetchError)
181
+
182
+ true
183
+ end
184
+
185
+ def filter_default_variants(variants)
186
+ variants.each do |key, value|
187
+ default = value&.metadata&.fetch('default', nil)
188
+ deployed = value&.metadata&.fetch('deployed', nil)
189
+ default = false if default.nil?
190
+ deployed = true if deployed.nil?
191
+ variants.delete(key) if default || !deployed
192
+ end
193
+ variants
194
+ end
195
+
196
+ private :filter_default_variants
143
197
  end
144
198
  end
@@ -1,6 +1,10 @@
1
1
  module AmplitudeExperiment
2
2
  # Variant
3
3
  class Variant
4
+ # The key of the variant determined by the flag configuration.
5
+ # @return [String] the value of variant key
6
+ attr_accessor :key
7
+
4
8
  # The value of the variant determined by the flag configuration.
5
9
  # @return [String] the value of variant value
6
10
  attr_accessor :value
@@ -9,17 +13,21 @@ module AmplitudeExperiment
9
13
  # @return [Object, nil] the value of variant payload
10
14
  attr_accessor :payload
11
15
 
16
+ attr_accessor :metadata
17
+
12
18
  # @param [String] value The value of the variant determined by the flag configuration.
13
19
  # @param [Object, nil] payload The attached payload, if any.
14
- def initialize(value, payload = nil)
20
+ def initialize(value, payload = nil, key = nil, metadata = nil)
21
+ @key = key
15
22
  @value = value
16
23
  @payload = payload
24
+ @metadata = metadata
17
25
  end
18
26
 
19
27
  # Determine if current variant equal other variant
20
28
  # @param [Variant] other
21
29
  def ==(other)
22
- value == other.value &&
30
+ key == other.key && value == other.value &&
23
31
  payload == other.payload
24
32
  end
25
33
  end
@@ -1,3 +1,3 @@
1
1
  module AmplitudeExperiment
2
- VERSION = '1.2.5'.freeze
2
+ VERSION = '1.3.0'.freeze
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: amplitude-experiment
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.5
4
+ version: 1.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Amplitude
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-11-30 00:00:00.000000000 Z
11
+ date: 2024-05-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: concurrent-ruby
@@ -176,6 +176,7 @@ files:
176
176
  - lib/amplitude/utils.rb
177
177
  - lib/amplitude/workers.rb
178
178
  - lib/experiment/cookie.rb
179
+ - lib/experiment/error.rb
179
180
  - lib/experiment/factory.rb
180
181
  - lib/experiment/local/assignment/assignment.rb
181
182
  - lib/experiment/local/assignment/assignment_config.rb