promoted-ruby-client 0.1.20 → 0.1.24

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: 340cf31fbc7680c1b9abb8df8dd1226e4a13fed103e21815afb82fb43b85f481
4
- data.tar.gz: d5448efcb375ac090847ac6c37fcda3b57babf0dca6043d82967e8ecdb42ae52
3
+ metadata.gz: 99f637dce3d3f85f13e8937bf586e6e9f5a11891b262e84a6e66d57a44bc6b09
4
+ data.tar.gz: 0c517b9e7b0049c6ae873c90db9536eae6b153367114cc50af887f36efcf79f2
5
5
  SHA512:
6
- metadata.gz: df18a2f73308fd9771b55a8762592a4041059b5d5fe72e0de07fa9566eb8627647eef75276a401c6f9da7d03bfc7158deb94bfd6b5824d22635a22b7d11848f0
7
- data.tar.gz: 7ed68c19270dcd13b8ed2347138aa845dd767d19bc257312e1a001f0e858879e75186142b9719b31e9c132d95fc7d48049baaf3e57b442f39f2b969cf2c835b8
6
+ metadata.gz: 640878d97d82424619a60ebf451db0f1501d15e625adfc2c53f3a47511e2661cb4d61bc8788d5b42f93c11f778411bc3bad59d5bab3fd787270a9b015f9968c3
7
+ data.tar.gz: e4a99864846f7d542e773d84897f9ce3ff9db842115d0ebd835f604a7763bebfa7c875656377e22f57442637f71a7d0663b098379e2603c5b6852f9696e626ce
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- promoted-ruby-client (0.1.20)
4
+ promoted-ruby-client (0.1.24)
5
5
  concurrent-ruby (~> 1)
6
6
  faraday (>= 0.9.0)
7
7
  faraday_middleware (>= 0.9.0)
data/README.md CHANGED
@@ -49,6 +49,7 @@ Name | Type | Description
49
49
  ```:perform_checks``` | Boolean | Whether or not to perform detailed input validation, defaults to true but may be disabled for performance
50
50
  ```:logger``` | Ruby Logger-compatible logger | Defaults to nil (no logging). Example: ```Logger.new(STDERR, :progname => 'promotedai')```
51
51
  ```:shadow_traffic_delivery_percent``` | Number between 0 and 1 | % of ```prepare_for_logging``` traffic that gets directed to Delivery API as "shadow traffic". Defaults to 0 (no shadow traffic).
52
+ ```:send_shadow_traffic_for_control``` | Boolean | If true, the ```deliver``` method will send shadow traffic for users in the CONTROL arm of an experiment. Defaults to true.
52
53
  ```:default_request_headers``` | Hash | Additional headers to send on the request beyond ```x-api-key```. Defaults to {}
53
54
  ```:default_only_log``` | Boolean | If true, the ```deliver``` method will not direct traffic to Delivery API but rather return a request suitable for logging. Defaults to false.
54
55
  ```:should_apply_treatment_func``` | Proc | Called during delivery, accepts an experiment and returns a Boolean indicating whether the request should be considered part of the control group (false) or in the experiment (true). If nil, the default behavior of checking the experiement ```:arm``` is applied.
@@ -62,6 +63,7 @@ Field Name | Type | Optional? | Description
62
63
  ---------- | ---- | --------- | -----------
63
64
  ```:user_id``` | String | Yes | The platform user id, cleared from Promoted logs.
64
65
  ```:log_user_id``` | String | Yes | A different user id (presumably a UUID) disconnected from the platform user id, good for working with unauthenticated users or implementing right-to-be-forgotten.
66
+ ```:is_internal_user``` | Boolean | Yes | If this user is a test user or not, defaults to false.
65
67
 
66
68
  ---
67
69
  ### CohortMembership
@@ -93,6 +95,8 @@ Field Name | Type | Optional? | Description
93
95
  ```:insertion_id``` | String | Yes | Generated by the SDK (*do not set*)
94
96
  ```:request_id``` | String | Yes | Generated by the SDK when needed (*do not set*)
95
97
  ```:content_id``` | String | No | Identifier for the content to be shown, must be set.
98
+ ```:retrieval_rank``` | Number | Yes | Optional original ranking of this content item.
99
+ ```:retrieval_score``` | Number | Yes | Optional original quality score of this content item.
96
100
  ```:properties``` | Properties | Yes | Any additional custom properties to associate. For v1 integrations, it is fine not to fill in all the properties.
97
101
  ---
98
102
  ### Size
data/dev.md CHANGED
@@ -4,5 +4,5 @@
4
4
  2. Get credentials for deployment from 1password.
5
5
  3. Modify `promoted-ruby-client.gemspec`'s push block.
6
6
  4. Run `gem build promoted-ruby-client.gemspec` to generate `gem`.
7
- 5. Run (using new output) `gem push promoted-ruby-client-0.1.20.gem`
7
+ 5. Run (using new output) `gem push promoted-ruby-client-0.1.24.gem`
8
8
  6. Update README with new version.
@@ -57,7 +57,7 @@ module Promoted
57
57
  params = {
58
58
  user_info: user_info,
59
59
  timing: timing,
60
- client_info: @client_info.merge({ :client_type => Promoted::Ruby::Client::CLIENT_TYPE['PLATFORM_SERVER'] }),
60
+ client_info: merge_client_info_defaults,
61
61
  device: @device,
62
62
  platform_id: @platform_id,
63
63
  view_id: @view_id,
@@ -100,12 +100,12 @@ module Promoted
100
100
  filled_in_copy
101
101
  end
102
102
 
103
- def log_request_params(include_insertions: true, include_request: true)
103
+ def log_request_params(include_delivery_log:, exec_server:)
104
104
  params = {
105
105
  user_info: user_info,
106
106
  timing: timing,
107
- client_info: @client_info,
108
- device: @device
107
+ client_info: merge_client_info_defaults,
108
+ device: @device,
109
109
  }
110
110
 
111
111
  if @experiment
@@ -113,14 +113,20 @@ module Promoted
113
113
  end
114
114
 
115
115
  # Log request allows for multiple requests but here we only send one.
116
- if include_request
116
+ if include_delivery_log
117
117
  request[:request_id] = request[:request_id] || @id_generator.newID
118
- params[:request] = [request]
119
- end
120
118
 
121
- if include_insertions
122
- params[:insertion] = compact_metrics_properties if include_insertions
123
- add_missing_ids_on_insertions! request, params[:insertion]
119
+ params[:delivery_log] = [{
120
+ execution: {
121
+ execution_server: exec_server
122
+ },
123
+ request: request,
124
+ response: {
125
+ insertion: insertions_with_compact_metrics_properties
126
+ }
127
+ }]
128
+
129
+ add_missing_ids_on_insertions! request, params[:delivery_log][0][:response][:insertion]
124
130
  end
125
131
 
126
132
  params.clean!
@@ -161,7 +167,7 @@ module Promoted
161
167
  end
162
168
 
163
169
  # TODO: This looks overly complicated.
164
- def compact_metrics_properties
170
+ def insertions_with_compact_metrics_properties
165
171
  @insertion = [] # insertion should be set according to the compact insertion
166
172
  paging = request[:paging] || {}
167
173
  size = paging[:size] ? paging[:size].to_i : 0
@@ -178,7 +184,6 @@ module Promoted
178
184
  insertion_obj = Hash[insertion_obj]
179
185
  insertion_obj[:user_info] = user_info
180
186
  insertion_obj[:timing] = timing
181
- insertion_obj[:insertion_id] = @id_generator.newID
182
187
  insertion_obj[:request_id] = request_id
183
188
  insertion_obj[:position] = offset + index
184
189
  insertion_obj = compact_one_insertion(insertion_obj, @to_compact_metrics_properties_func)
@@ -187,18 +192,31 @@ module Promoted
187
192
  @insertion
188
193
  end
189
194
 
195
+ def add_missing_insertion_ids! insertions
196
+ insertions.each do |insertion|
197
+ insertion[:insertion_id] = @id_generator.newID if not insertion[:insertion_id]
198
+ end
199
+ end
200
+
190
201
  def client_request_id
191
202
  request[:client_request_id]
192
203
  end
193
204
 
194
205
  private
195
206
 
207
+ def merge_client_info_defaults
208
+ return @client_info.merge({
209
+ :client_type => Promoted::Ruby::Client::CLIENT_TYPE['PLATFORM_SERVER'],
210
+ :traffic_type => Promoted::Ruby::Client::TRAFFIC_TYPE['PRODUCTION']
211
+ })
212
+ end
213
+
196
214
  def add_missing_ids_on_insertions! request, insertions
197
215
  insertions.each do |insertion|
198
- insertion[:insertion_id] = @id_generator.newID if not insertion[:insertion_id]
199
216
  insertion[:session_id] = request[:session_id] if request[:session_id]
200
217
  insertion[:request_id] = request[:request_id] if request[:request_id]
201
218
  end
219
+ add_missing_insertion_ids! insertions
202
220
  end
203
221
 
204
222
  # A list of the response Insertions. This client expects lists to be truncated
@@ -14,6 +14,10 @@ module Promoted
14
14
  {
15
15
  :name => :log_user_id,
16
16
  :type => String
17
+ },
18
+ {
19
+ :name => :is_internal_user,
20
+ :type => [TrueClass, FalseClass]
17
21
  }
18
22
  ]
19
23
  )
@@ -55,6 +59,14 @@ module Promoted
55
59
  {
56
60
  :name => :delivery_score,
57
61
  :type => Integer
62
+ },
63
+ {
64
+ :name => :retrieval_rank,
65
+ :type => Integer
66
+ },
67
+ {
68
+ :name => :retrieval_score,
69
+ :type => Float
58
70
  }
59
71
  ]
60
72
  )
@@ -133,7 +145,6 @@ module Promoted
133
145
  req[:full_insertion].each do |insertion_hash|
134
146
  raise ValidationError.new("Insertion.requestId should not be set") if insertion_hash[:request_id]
135
147
  raise ValidationError.new("'Insertion.insertionId should not be set") if insertion_hash[:insertion_id]
136
- raise ValidationError.new("Insertion.deliveryScore should not be set") if insertion_hash[:delivery_score]
137
148
  end
138
149
  end
139
150
 
@@ -147,7 +158,11 @@ module Promoted
147
158
 
148
159
  # If a field is provided as non-nil, it should be of the correct type.
149
160
  if field[:type] && obj.has_key?(field[:name]) && obj[field[:name]] != nil then
150
- raise ValidationError.new(field[:name].to_s + " should be a " + field[:type].to_s) if !obj[field[:name]].is_a?(field[:type])
161
+ if field[:type].is_a?(Array) then
162
+ raise ValidationError.new(field[:name].to_s + " should be one of " + field[:type].to_s) if !field[:type].include?(obj[field[:name]].class)
163
+ else
164
+ raise ValidationError.new(field[:name].to_s + " should be a " + field[:type].to_s) if !obj[field[:name]].is_a?(field[:type])
165
+ end
151
166
  end
152
167
  }
153
168
  end
@@ -1,7 +1,7 @@
1
1
  module Promoted
2
2
  module Ruby
3
3
  module Client
4
- VERSION = "0.1.20"
4
+ VERSION = "0.1.24"
5
5
  end
6
6
  end
7
7
  end
@@ -19,7 +19,8 @@ module Promoted
19
19
  class Error < StandardError; end
20
20
 
21
21
  attr_reader :perform_checks, :default_only_log, :delivery_timeout_millis, :metrics_timeout_millis, :should_apply_treatment_func,
22
- :default_request_headers, :http_client, :logger, :shadow_traffic_delivery_percent, :async_shadow_traffic
22
+ :default_request_headers, :http_client, :logger, :shadow_traffic_delivery_percent, :async_shadow_traffic,
23
+ :send_shadow_traffic_for_control
23
24
 
24
25
  attr_accessor :request_logging_on, :enabled
25
26
 
@@ -79,6 +80,11 @@ module Promoted
79
80
  @async_shadow_traffic = params[:async_shadow_traffic] || false
80
81
  end
81
82
 
83
+ @send_shadow_traffic_for_control = true
84
+ if params[:send_shadow_traffic_for_control] != nil
85
+ @send_shadow_traffic_for_control = params[:send_shadow_traffic_for_control] || false
86
+ end
87
+
82
88
  @pool = nil
83
89
  if @async_shadow_traffic
84
90
  # Thread pool to process delivery of shadow traffic. Will silently drop excess requests beyond the queue
@@ -161,9 +167,8 @@ module Promoted
161
167
  cohort_membership_to_log = delivery_request_builder.new_cohort_membership_to_log
162
168
 
163
169
  if should_apply_treatment(cohort_membership_to_log)
164
- delivery_request_params = delivery_request_builder.delivery_request_params
165
-
166
- # Call Delivery API
170
+ # Call Delivery API to get insertions to use
171
+ delivery_request_params = delivery_request_builder.delivery_request_params
167
172
  begin
168
173
  response = send_request(delivery_request_params, @delivery_endpoint, @delivery_timeout_millis, @delivery_api_key, headers)
169
174
  rescue StandardError => err
@@ -172,20 +177,25 @@ module Promoted
172
177
  deliver_err = true
173
178
  @logger.error("Error calling delivery: " + err.message) if @logger
174
179
  end
175
-
176
- insertions_from_delivery = (response != nil && !deliver_err);
177
- response_insertions = delivery_request_builder.fill_details_from_response(
178
- response && response[:insertion] || [])
180
+ elsif @send_shadow_traffic_for_control
181
+ # Call Delivery API to send shadow traffic. This will create the request params with traffic type set.
182
+ deliver_shadow_traffic args, headers
179
183
  end
184
+
185
+ insertions_from_delivery = (response != nil && !deliver_err);
186
+ response_insertions = delivery_request_builder.fill_details_from_response(
187
+ response && response[:insertion] || [])
180
188
  end
181
189
 
182
190
  request_to_log = nil
183
191
  if !insertions_from_delivery then
184
192
  request_to_log = delivery_request_builder.request
185
- response_insertions = @pager.apply_paging(delivery_request_builder.full_insertion, Promoted::Ruby::Client::INSERTION_PAGING_TYPE['UNPAGED'], delivery_request_builder.request[:paging])
193
+ response_insertions = build_sdk_response_insertions(delivery_request_builder)
186
194
  end
187
195
 
188
196
  log_req = nil
197
+ exec_server = (insertions_from_delivery ? Promoted::Ruby::Client::EXECUTION_SERVER['API'] : Promoted::Ruby::Client::EXECUTION_SERVER['SDK'])
198
+
189
199
  # We only return a log request if there's a request or cohort to log.
190
200
  if request_to_log || cohort_membership_to_log
191
201
  log_request_builder = RequestBuilder.new
@@ -204,14 +214,14 @@ module Promoted
204
214
  # On a successful delivery request, we don't log the insertions
205
215
  # or the request since they are logged on the server-side.
206
216
  log_req = log_request_builder.log_request_params(
207
- include_insertions: !insertions_from_delivery,
208
- include_request: !insertions_from_delivery)
217
+ include_delivery_log: !insertions_from_delivery,
218
+ exec_server: exec_server)
209
219
  end
210
220
 
211
221
  client_response = {
212
222
  insertion: response_insertions,
213
223
  log_request: log_req,
214
- execution_server: insertions_from_delivery ? Promoted::Ruby::Client::EXECUTION_SERVER['API'] : Promoted::Ruby::Client::EXECUTION_SERVER['SDK'],
224
+ execution_server: exec_server,
215
225
  client_request_id: delivery_request_builder.client_request_id
216
226
  }
217
227
  return client_response
@@ -250,7 +260,9 @@ module Promoted
250
260
  deliver_shadow_traffic args, headers
251
261
  end
252
262
 
253
- log_request_builder.log_request_params
263
+ log_request_builder.log_request_params(
264
+ include_delivery_log: true,
265
+ exec_server: Promoted::Ruby::Client::EXECUTION_SERVER['SDK'])
254
266
  end
255
267
 
256
268
  ##
@@ -266,6 +278,14 @@ module Promoted
266
278
 
267
279
  private
268
280
 
281
+ ##
282
+ # Creates response insertions for SDK-side delivery, when we don't get response insertions from Delivery API.
283
+ def build_sdk_response_insertions delivery_request_builder
284
+ response_insertions = @pager.apply_paging(delivery_request_builder.full_insertion, Promoted::Ruby::Client::INSERTION_PAGING_TYPE['UNPAGED'], delivery_request_builder.request[:paging])
285
+ delivery_request_builder.add_missing_insertion_ids! response_insertions
286
+ return response_insertions
287
+ end
288
+
269
289
  def do_warmup
270
290
  if !@delivery_endpoint
271
291
  # Warmup only supported when delivery is enabled.
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: promoted-ruby-client
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.20
4
+ version: 0.1.24
5
5
  platform: ruby
6
6
  authors:
7
7
  - scottmcmaster
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-08-19 00:00:00.000000000 Z
11
+ date: 2021-10-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: faraday
@@ -169,7 +169,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
169
169
  - !ruby/object:Gem::Version
170
170
  version: '0'
171
171
  requirements: []
172
- rubygems_version: 3.2.24
172
+ rubygems_version: 3.0.3
173
173
  signing_key:
174
174
  specification_version: 4
175
175
  summary: A Ruby Client to contact Promoted APIs.