amplitude-experiment 1.2.5 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
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