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 +4 -4
- data/Gemfile.lock +1 -1
- data/README.md +4 -0
- data/dev.md +1 -1
- data/lib/promoted/ruby/client/request_builder.rb +31 -13
- data/lib/promoted/ruby/client/validator.rb +17 -2
- data/lib/promoted/ruby/client/version.rb +1 -1
- data/lib/promoted/ruby/client.rb +33 -13
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 99f637dce3d3f85f13e8937bf586e6e9f5a11891b262e84a6e66d57a44bc6b09
|
4
|
+
data.tar.gz: 0c517b9e7b0049c6ae873c90db9536eae6b153367114cc50af887f36efcf79f2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 640878d97d82424619a60ebf451db0f1501d15e625adfc2c53f3a47511e2661cb4d61bc8788d5b42f93c11f778411bc3bad59d5bab3fd787270a9b015f9968c3
|
7
|
+
data.tar.gz: e4a99864846f7d542e773d84897f9ce3ff9db842115d0ebd835f604a7763bebfa7c875656377e22f57442637f71a7d0663b098379e2603c5b6852f9696e626ce
|
data/Gemfile.lock
CHANGED
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.
|
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:
|
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(
|
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:
|
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
|
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
|
-
|
122
|
-
|
123
|
-
|
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
|
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
|
-
|
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
|
data/lib/promoted/ruby/client.rb
CHANGED
@@ -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
|
-
|
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
|
-
|
177
|
-
|
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 =
|
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
|
-
|
208
|
-
|
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:
|
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.
|
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-
|
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.
|
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.
|