promoted-ruby-client 0.1.24 → 1.0.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 +4 -4
- data/.gitignore +3 -1
- data/Gemfile.lock +1 -1
- data/README.md +9 -23
- data/dev.md +1 -1
- data/lib/promoted/ruby/client/request_builder.rb +22 -72
- data/lib/promoted/ruby/client/validator.rb +28 -10
- data/lib/promoted/ruby/client/version.rb +2 -1
- data/lib/promoted/ruby/client.rb +40 -61
- data/promoted-ruby-client.gemspec +3 -1
- metadata +6 -7
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: d69f1cdf504a586671a915d42a1b65c71aeb97f783ddf42dc17693a6450244c6
|
|
4
|
+
data.tar.gz: 52b544d8e6919363728646bca71603636856b548cf0c139e5028ece5834c90cb
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 39b89adc216fc01fd13b7be8e11d241460fae6f0217c944bace0d59b67c587c83c86504d43ed2b01b85404db56d3209f5809900a2fd803d1252953b5b3523411
|
|
7
|
+
data.tar.gz: ef7f09600fbc73fab498b290957a3ddbfc32bb2b1ecdb7750194c526e48679cf9e1b7b504edc0c20f733929e64721db71c23bcdd743c61f3c6549c8a8882d0d3
|
data/.gitignore
CHANGED
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
|
@@ -54,6 +54,7 @@ Name | Type | Description
|
|
|
54
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.
|
|
55
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.
|
|
56
56
|
```:warmup``` | Boolean | If true, the client will prime the `Net::HTTP::Persistent` connection pool on construction; this can make the first few calls to Promoted complete faster. Defaults to false.
|
|
57
|
+
```:max_request_insertions``` | Number | Maximum number of request insertions that will be passed to Delivery API on a single request (any more will be truncated by the SDK). Defaults to 1000.
|
|
57
58
|
|
|
58
59
|
## Data Types
|
|
59
60
|
|
|
@@ -152,6 +153,7 @@ Field Name | Type | Optional? | Description
|
|
|
152
153
|
```:user_agent``` | String | Yes | Browser user agent string
|
|
153
154
|
```:viewport_size``` | Size | Yes | Size of the browser viewport
|
|
154
155
|
```:client_hints``` | ClientHints | Yes | HTTP client hints structure
|
|
156
|
+
```referrer``` | String | Yes | Request referrer
|
|
155
157
|
---
|
|
156
158
|
### Device
|
|
157
159
|
Information about the user's device.
|
|
@@ -180,13 +182,6 @@ Field Name | Type | Optional? | Description
|
|
|
180
182
|
```:paging``` | Paging | Yes | Paging parameters (see TODO)
|
|
181
183
|
```:device``` | Device | Yes | Device information (as available)
|
|
182
184
|
---
|
|
183
|
-
### MetricsRequest
|
|
184
|
-
Input to ```prepare_for_logging```
|
|
185
|
-
Field Name | Type | Optional? | Description
|
|
186
|
-
---------- | ---- | --------- | -----------
|
|
187
|
-
```:request``` | Request | No | The underlying request for content.
|
|
188
|
-
```:full_insertion``` | [] of Insertion | No | The proposed list of insertions.
|
|
189
|
-
---
|
|
190
185
|
|
|
191
186
|
### DeliveryRequest
|
|
192
187
|
Input to ```deliver```
|
|
@@ -194,7 +189,6 @@ Field Name | Type | Optional? | Description
|
|
|
194
189
|
---------- | ---- | --------- | -----------
|
|
195
190
|
```:experiment``` | CohortMembership | Yes | A cohort to evaluation in experimentation.
|
|
196
191
|
```:request``` | Request | No | The underlying request for content.
|
|
197
|
-
```:full_insertion``` | [] of Insertion | No | The proposed list of insertions with all metadata, will be compacted before forwarding to Promoted.
|
|
198
192
|
```:only_log``` | Boolean | Yes | Defaults to false. Set to true to override whether Delivery API is called for this request.
|
|
199
193
|
---
|
|
200
194
|
|
|
@@ -286,28 +280,20 @@ metrics_request = {
|
|
|
286
280
|
:struct => {
|
|
287
281
|
:active => true
|
|
288
282
|
}
|
|
289
|
-
}
|
|
283
|
+
},
|
|
284
|
+
:insertion => insertions
|
|
290
285
|
},
|
|
291
|
-
:
|
|
286
|
+
:only_log => true,
|
|
292
287
|
}
|
|
293
288
|
|
|
294
|
-
# OPTIONAL: You can pass a custom function to "compact" insertions before metrics logging.
|
|
295
|
-
# Note that the PromotedClient has a class method helper, remove_all_properties, that does
|
|
296
|
-
# an implementation of this, returning nil to remove ALL properties.
|
|
297
|
-
to_compact_metrics_properties_func = Proc.new do |properties|
|
|
298
|
-
properties[:struct].delete(:active)
|
|
299
|
-
properties
|
|
300
|
-
end
|
|
301
|
-
# metrics_request[:to_compact_metrics_properties_func] = to_compact_metrics_properties_func
|
|
302
|
-
|
|
303
289
|
# Create a client
|
|
304
290
|
client = Promoted::Ruby::Client::PromotedClient.new
|
|
305
291
|
|
|
306
292
|
# Build a log request
|
|
307
|
-
|
|
293
|
+
client_response = client.deliver(metrics_request)
|
|
308
294
|
|
|
309
295
|
# Log (assuming you have configured your client with a :metrics_endpoint)
|
|
310
|
-
client.send_log_request(log_request)
|
|
296
|
+
client.send_log_request(client_response[:log_request]) if client_response[:log_request]
|
|
311
297
|
```
|
|
312
298
|
|
|
313
299
|
## Delivery API
|
|
@@ -330,9 +316,9 @@ delivery_request = {
|
|
|
330
316
|
:struct => {
|
|
331
317
|
:active => true
|
|
332
318
|
}
|
|
333
|
-
}
|
|
319
|
+
},
|
|
320
|
+
:insertion => insertions,
|
|
334
321
|
},
|
|
335
|
-
:full_insertion => insertions,
|
|
336
322
|
:only_log => false
|
|
337
323
|
}
|
|
338
324
|
|
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-1.0.1.gem`
|
|
8
8
|
6. Update README with new version.
|
|
@@ -3,10 +3,9 @@ module Promoted
|
|
|
3
3
|
module Client
|
|
4
4
|
class RequestBuilder
|
|
5
5
|
attr_reader :session_id, :only_log, :experiment, :client_info, :device,
|
|
6
|
-
:view_id, :insertion, :
|
|
7
|
-
:request_id, :full_insertion, :use_case, :request, :to_compact_metrics_properties_func
|
|
6
|
+
:view_id, :insertion, :request_id, :use_case, :request
|
|
8
7
|
|
|
9
|
-
attr_accessor :timing, :user_info, :platform_id
|
|
8
|
+
attr_accessor :timing, :user_info, :platform_id, :insertion
|
|
10
9
|
|
|
11
10
|
def initialize args = {}
|
|
12
11
|
if args[:id_generator]
|
|
@@ -27,11 +26,9 @@ module Promoted
|
|
|
27
26
|
@device = request[:device] || {}
|
|
28
27
|
@view_id = request[:view_id]
|
|
29
28
|
@use_case = Promoted::Ruby::Client::USE_CASES[request[:use_case]] || Promoted::Ruby::Client::USE_CASES['UNKNOWN_USE_CASE']
|
|
30
|
-
@
|
|
29
|
+
@insertion = request[:insertion] || []
|
|
31
30
|
@user_info = request[:user_info] || { :user_id => nil, :log_user_id => nil}
|
|
32
|
-
@timing = request[:timing] || { :client_log_timestamp => Time.now.to_i }
|
|
33
|
-
@to_compact_metrics_properties_func = args[:to_compact_metrics_properties_func]
|
|
34
|
-
@to_compact_delivery_properties_func = args[:to_compact_delivery_properties_func]
|
|
31
|
+
@timing = request[:timing] || { :client_log_timestamp => (Time.now.to_f * 1000).to_i }
|
|
35
32
|
|
|
36
33
|
# If the user didn't create a client request id, we do it for them.
|
|
37
34
|
request[:client_request_id] = request[:client_request_id] || @id_generator.newID
|
|
@@ -68,7 +65,7 @@ module Promoted
|
|
|
68
65
|
paging: request[:paging],
|
|
69
66
|
client_request_id: client_request_id
|
|
70
67
|
}
|
|
71
|
-
params[:insertion] =
|
|
68
|
+
params[:insertion] = insertion
|
|
72
69
|
|
|
73
70
|
params.clean!
|
|
74
71
|
end
|
|
@@ -81,7 +78,7 @@ module Promoted
|
|
|
81
78
|
response_insertions = []
|
|
82
79
|
end
|
|
83
80
|
|
|
84
|
-
props = @
|
|
81
|
+
props = @insertion.each_with_object({}) do |insertion, hash|
|
|
85
82
|
if insertion.has_key?(:properties)
|
|
86
83
|
# Don't add nil properties to response insertions.
|
|
87
84
|
hash[insertion[:content_id]] = insertion[:properties]
|
|
@@ -118,78 +115,46 @@ module Promoted
|
|
|
118
115
|
|
|
119
116
|
params[:delivery_log] = [{
|
|
120
117
|
execution: {
|
|
121
|
-
execution_server: exec_server
|
|
118
|
+
execution_server: exec_server,
|
|
119
|
+
server_version: Promoted::Ruby::Client::SERVER_VERSION
|
|
122
120
|
},
|
|
123
121
|
request: request,
|
|
124
122
|
response: {
|
|
125
|
-
insertion:
|
|
123
|
+
insertion: response_insertion
|
|
126
124
|
}
|
|
127
125
|
}]
|
|
128
126
|
|
|
129
|
-
|
|
127
|
+
add_missing_insertion_ids! params[:delivery_log][0][:response][:insertion]
|
|
130
128
|
end
|
|
131
129
|
|
|
132
130
|
params.clean!
|
|
133
131
|
end
|
|
134
132
|
|
|
135
|
-
def compact_one_insertion(insertion, compact_func)
|
|
136
|
-
return insertion if (!compact_func || !insertion[:properties])
|
|
137
|
-
|
|
138
|
-
# Only need a copy if there are properties to compact.
|
|
139
|
-
compact_insertion = insertion.dup
|
|
140
|
-
|
|
141
|
-
# Let the custom function work with a deep copy of the properties.
|
|
142
|
-
# There's really no way to work with a shallow copy and still be able
|
|
143
|
-
# to restore the correct insertion properties after a call to delivery.
|
|
144
|
-
new_props = Marshal.load(Marshal.dump(insertion[:properties]))
|
|
145
|
-
compact_insertion[:properties] = compact_func.call(new_props)
|
|
146
|
-
compact_insertion.clean!
|
|
147
|
-
return compact_insertion
|
|
148
|
-
end
|
|
149
|
-
|
|
150
|
-
def insertions_with_compact_props(compact_func)
|
|
151
|
-
if !compact_func
|
|
152
|
-
# Nothing to do, avoid copying the whole array.
|
|
153
|
-
full_insertion
|
|
154
|
-
else
|
|
155
|
-
compact_insertions = Array.new(full_insertion.length)
|
|
156
|
-
full_insertion.each_with_index {|insertion, index|
|
|
157
|
-
compact_insertions[index] = compact_one_insertion(insertion, compact_func)
|
|
158
|
-
}
|
|
159
|
-
compact_insertions
|
|
160
|
-
end
|
|
161
|
-
end
|
|
162
|
-
|
|
163
133
|
def ensure_client_timestamp
|
|
164
134
|
if timing[:client_log_timestamp].nil?
|
|
165
|
-
timing[:client_log_timestamp] = Time.now.to_i
|
|
135
|
+
timing[:client_log_timestamp] = (Time.now.to_f * 1000).to_i
|
|
166
136
|
end
|
|
167
137
|
end
|
|
168
138
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
@insertion = [] # insertion should be set according to the compact insertion
|
|
139
|
+
def response_insertion
|
|
140
|
+
@response_insertions = []
|
|
172
141
|
paging = request[:paging] || {}
|
|
173
142
|
size = paging[:size] ? paging[:size].to_i : 0
|
|
174
143
|
if size <= 0
|
|
175
|
-
size =
|
|
144
|
+
size = insertion.length()
|
|
176
145
|
end
|
|
177
146
|
offset = paging[:offset] ? paging[:offset].to_i : 0
|
|
178
147
|
|
|
179
|
-
|
|
148
|
+
insertion.each_with_index do |insertion_obj, index|
|
|
180
149
|
# TODO - this does not look performant.
|
|
181
|
-
break if @
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
insertion_obj[:request_id] = request_id
|
|
188
|
-
insertion_obj[:position] = offset + index
|
|
189
|
-
insertion_obj = compact_one_insertion(insertion_obj, @to_compact_metrics_properties_func)
|
|
190
|
-
@insertion << insertion_obj.clean!
|
|
150
|
+
break if @response_insertions.length() >= size
|
|
151
|
+
response_insertion = Hash[]
|
|
152
|
+
response_insertion[:content_id] = insertion_obj[:content_id]
|
|
153
|
+
response_insertion[:position] = offset + index
|
|
154
|
+
response_insertion[:insertion_id] = insertion_obj[:insertion_id]
|
|
155
|
+
@response_insertions << response_insertion.clean!
|
|
191
156
|
end
|
|
192
|
-
@
|
|
157
|
+
@response_insertions
|
|
193
158
|
end
|
|
194
159
|
|
|
195
160
|
def add_missing_insertion_ids! insertions
|
|
@@ -210,21 +175,6 @@ module Promoted
|
|
|
210
175
|
:traffic_type => Promoted::Ruby::Client::TRAFFIC_TYPE['PRODUCTION']
|
|
211
176
|
})
|
|
212
177
|
end
|
|
213
|
-
|
|
214
|
-
def add_missing_ids_on_insertions! request, insertions
|
|
215
|
-
insertions.each do |insertion|
|
|
216
|
-
insertion[:session_id] = request[:session_id] if request[:session_id]
|
|
217
|
-
insertion[:request_id] = request[:request_id] if request[:request_id]
|
|
218
|
-
end
|
|
219
|
-
add_missing_insertion_ids! insertions
|
|
220
|
-
end
|
|
221
|
-
|
|
222
|
-
# A list of the response Insertions. This client expects lists to be truncated
|
|
223
|
-
# already to request.paging.size. If not truncated, this client will truncate
|
|
224
|
-
# the list.
|
|
225
|
-
def insertion
|
|
226
|
-
@insertion
|
|
227
|
-
end
|
|
228
178
|
end
|
|
229
179
|
end
|
|
230
180
|
end
|
|
@@ -99,6 +99,7 @@ module Promoted
|
|
|
99
99
|
},
|
|
100
100
|
{
|
|
101
101
|
:name => :insertion,
|
|
102
|
+
:required => true,
|
|
102
103
|
:type => Array
|
|
103
104
|
}
|
|
104
105
|
]
|
|
@@ -115,6 +116,25 @@ module Promoted
|
|
|
115
116
|
end
|
|
116
117
|
end
|
|
117
118
|
|
|
119
|
+
def validate_response!(res)
|
|
120
|
+
validate_fields!(
|
|
121
|
+
res,
|
|
122
|
+
"response",
|
|
123
|
+
[
|
|
124
|
+
{
|
|
125
|
+
:name => :request_id,
|
|
126
|
+
:required => true,
|
|
127
|
+
:type => String
|
|
128
|
+
}
|
|
129
|
+
]
|
|
130
|
+
)
|
|
131
|
+
|
|
132
|
+
if !res.key?(:insertion) then
|
|
133
|
+
res[:insertion] = []
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
# TODO - delete?
|
|
118
138
|
def validate_metrics_request!(metrics_req)
|
|
119
139
|
validate_fields!(
|
|
120
140
|
metrics_req,
|
|
@@ -123,31 +143,29 @@ module Promoted
|
|
|
123
143
|
{
|
|
124
144
|
:name => :request,
|
|
125
145
|
:required => true
|
|
126
|
-
},
|
|
127
|
-
{
|
|
128
|
-
:name => :full_insertion,
|
|
129
|
-
:required => true,
|
|
130
|
-
:type => Array
|
|
131
146
|
}
|
|
132
147
|
]
|
|
133
148
|
)
|
|
134
149
|
|
|
135
150
|
validate_request!(metrics_req[:request])
|
|
136
|
-
metrics_req[:full_insertion].each {|ins|
|
|
137
|
-
validate_insertion! ins
|
|
138
|
-
}
|
|
139
151
|
end
|
|
140
152
|
|
|
141
153
|
def check_that_log_ids_not_set! req
|
|
154
|
+
raise ValidationError.new("Request should be set") if !req[:request]
|
|
142
155
|
raise ValidationError.new("Request.requestId should not be set") if req.dig(:request, :request_id)
|
|
143
|
-
raise ValidationError.new("Do not set Request.insertion. Set full_insertion.") if req[:insertion]
|
|
144
156
|
|
|
145
|
-
req[:
|
|
157
|
+
req[:request][:insertion].each do |insertion_hash|
|
|
146
158
|
raise ValidationError.new("Insertion.requestId should not be set") if insertion_hash[:request_id]
|
|
147
159
|
raise ValidationError.new("'Insertion.insertionId should not be set") if insertion_hash[:insertion_id]
|
|
148
160
|
end
|
|
149
161
|
end
|
|
150
162
|
|
|
163
|
+
def check_that_content_ids_are_set! req
|
|
164
|
+
req[:request][:insertion].each do |insertion_hash|
|
|
165
|
+
raise ValidationError.new("Insertion.contentId should be set") if !insertion_hash[:content_id] || insertion_hash[:content_id].empty?
|
|
166
|
+
end
|
|
167
|
+
end
|
|
168
|
+
|
|
151
169
|
private
|
|
152
170
|
|
|
153
171
|
def validate_fields!(obj, obj_name, fields)
|
data/lib/promoted/ruby/client.rb
CHANGED
|
@@ -8,6 +8,7 @@ module Promoted
|
|
|
8
8
|
|
|
9
9
|
DEFAULT_DELIVERY_TIMEOUT_MILLIS = 250
|
|
10
10
|
DEFAULT_METRICS_TIMEOUT_MILLIS = 3000
|
|
11
|
+
DEFAULT_MAX_REQUEST_INSERTIONS = 1000
|
|
11
12
|
DEFAULT_DELIVERY_ENDPOINT = "http://delivery.example.com"
|
|
12
13
|
DEFAULT_METRICS_ENDPOINT = "http://metrics.example.com"
|
|
13
14
|
|
|
@@ -20,7 +21,7 @@ module Promoted
|
|
|
20
21
|
|
|
21
22
|
attr_reader :perform_checks, :default_only_log, :delivery_timeout_millis, :metrics_timeout_millis, :should_apply_treatment_func,
|
|
22
23
|
:default_request_headers, :http_client, :logger, :shadow_traffic_delivery_percent, :async_shadow_traffic,
|
|
23
|
-
:send_shadow_traffic_for_control
|
|
24
|
+
:send_shadow_traffic_for_control, :max_request_insertions
|
|
24
25
|
|
|
25
26
|
attr_accessor :request_logging_on, :enabled
|
|
26
27
|
|
|
@@ -30,14 +31,6 @@ module Promoted
|
|
|
30
31
|
@enabled
|
|
31
32
|
end
|
|
32
33
|
|
|
33
|
-
##
|
|
34
|
-
# A common compact properties method implementation.
|
|
35
|
-
def self.remove_all_properties
|
|
36
|
-
Proc.new do |properties|
|
|
37
|
-
nil
|
|
38
|
-
end
|
|
39
|
-
end
|
|
40
|
-
|
|
41
34
|
##
|
|
42
35
|
# Create and configure a new Promoted client.
|
|
43
36
|
def initialize(params={})
|
|
@@ -85,6 +78,8 @@ module Promoted
|
|
|
85
78
|
@send_shadow_traffic_for_control = params[:send_shadow_traffic_for_control] || false
|
|
86
79
|
end
|
|
87
80
|
|
|
81
|
+
@max_request_insertions = params[:max_request_insertions] || DEFAULT_MAX_REQUEST_INSERTIONS
|
|
82
|
+
|
|
88
83
|
@pool = nil
|
|
89
84
|
if @async_shadow_traffic
|
|
90
85
|
# Thread pool to process delivery of shadow traffic. Will silently drop excess requests beyond the queue
|
|
@@ -124,7 +119,7 @@ module Promoted
|
|
|
124
119
|
# Respect the enabled state
|
|
125
120
|
if !@enabled
|
|
126
121
|
return {
|
|
127
|
-
insertion: @pager.apply_paging(args[:
|
|
122
|
+
insertion: @pager.apply_paging(args[:request][:insertion], Promoted::Ruby::Client::INSERTION_PAGING_TYPE['UNPAGED'], args[:request][:paging])
|
|
128
123
|
# No log request returned when disabled
|
|
129
124
|
}
|
|
130
125
|
end
|
|
@@ -132,14 +127,22 @@ module Promoted
|
|
|
132
127
|
delivery_request_builder = RequestBuilder.new
|
|
133
128
|
delivery_request_builder.set_request_params(args)
|
|
134
129
|
|
|
130
|
+
only_log = delivery_request_builder.only_log != nil ? delivery_request_builder.only_log : @default_only_log
|
|
131
|
+
|
|
132
|
+
# Gets modified depending on the call.
|
|
133
|
+
should_send_shadow_traffic = @shadow_traffic_delivery_percent > 0
|
|
135
134
|
# perform_checks raises errors.
|
|
136
135
|
if @perform_checks
|
|
137
136
|
perform_common_checks!(args)
|
|
137
|
+
if !only_log && args[:insertion_page_type] == Promoted::Ruby::Client::INSERTION_PAGING_TYPE['PRE_PAGED'] then
|
|
138
|
+
err = DeliveryInsertionPageType.new
|
|
139
|
+
@logger.error(err) if @logger
|
|
140
|
+
raise err
|
|
141
|
+
end
|
|
138
142
|
|
|
139
|
-
if args[:insertion_page_type]
|
|
140
|
-
|
|
141
|
-
@logger.error(
|
|
142
|
-
raise err
|
|
143
|
+
if should_send_shadow_traffic && args[:insertion_page_type] != Promoted::Ruby::Client::INSERTION_PAGING_TYPE['UNPAGED'] then
|
|
144
|
+
should_send_shadow_traffic = false
|
|
145
|
+
@logger.error(ShadowTrafficInsertionPageType.new) if @logger
|
|
143
146
|
end
|
|
144
147
|
end
|
|
145
148
|
|
|
@@ -149,11 +152,16 @@ module Promoted
|
|
|
149
152
|
cohort_membership_to_log = nil
|
|
150
153
|
insertions_from_delivery = false
|
|
151
154
|
|
|
152
|
-
only_log = delivery_request_builder.only_log != nil ? delivery_request_builder.only_log : @default_only_log
|
|
153
155
|
deliver_err = false
|
|
154
156
|
|
|
157
|
+
# Trim any request insertions over the maximum allowed.
|
|
158
|
+
if delivery_request_builder.insertion.length > @max_request_insertions then
|
|
159
|
+
@logger.warn("Exceeded max request insertions, trimming") if @logger
|
|
160
|
+
delivery_request_builder.insertion = delivery_request_builder.insertion[0, @max_request_insertions]
|
|
161
|
+
end
|
|
162
|
+
|
|
155
163
|
begin
|
|
156
|
-
@pager.validate_paging(delivery_request_builder.
|
|
164
|
+
@pager.validate_paging(delivery_request_builder.insertion, delivery_request_builder.request[:paging])
|
|
157
165
|
rescue InvalidPagingError => err
|
|
158
166
|
# Invalid input, log and do SDK-side delivery.
|
|
159
167
|
@logger.warn(err) if @logger
|
|
@@ -171,22 +179,29 @@ module Promoted
|
|
|
171
179
|
delivery_request_params = delivery_request_builder.delivery_request_params
|
|
172
180
|
begin
|
|
173
181
|
response = send_request(delivery_request_params, @delivery_endpoint, @delivery_timeout_millis, @delivery_api_key, headers)
|
|
182
|
+
@validator.validate_response!(response)
|
|
174
183
|
rescue StandardError => err
|
|
175
184
|
# Currently we don't propagate errors to the SDK caller, but rather default to returning
|
|
176
185
|
# the request insertions.
|
|
177
186
|
deliver_err = true
|
|
178
187
|
@logger.error("Error calling delivery: " + err.message) if @logger
|
|
179
188
|
end
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
189
|
+
should_send_shadow_traffic = false
|
|
190
|
+
else
|
|
191
|
+
should_send_shadow_traffic &&= @send_shadow_traffic_for_control
|
|
183
192
|
end
|
|
184
193
|
|
|
185
194
|
insertions_from_delivery = (response != nil && !deliver_err);
|
|
186
195
|
response_insertions = delivery_request_builder.fill_details_from_response(
|
|
187
196
|
response && response[:insertion] || [])
|
|
188
197
|
end
|
|
189
|
-
|
|
198
|
+
|
|
199
|
+
should_send_shadow_traffic &&= should_send_as_shadow_traffic?
|
|
200
|
+
if should_send_shadow_traffic then
|
|
201
|
+
# Call Delivery API to send shadow traffic. This will create the request params with traffic type set.
|
|
202
|
+
deliver_shadow_traffic args, headers
|
|
203
|
+
end
|
|
204
|
+
|
|
190
205
|
request_to_log = nil
|
|
191
206
|
if !insertions_from_delivery then
|
|
192
207
|
request_to_log = delivery_request_builder.request
|
|
@@ -200,7 +215,7 @@ module Promoted
|
|
|
200
215
|
if request_to_log || cohort_membership_to_log
|
|
201
216
|
log_request_builder = RequestBuilder.new
|
|
202
217
|
log_request = {
|
|
203
|
-
:
|
|
218
|
+
:insertion => response_insertions,
|
|
204
219
|
:experiment => cohort_membership_to_log,
|
|
205
220
|
:request => request_to_log
|
|
206
221
|
}
|
|
@@ -227,44 +242,6 @@ module Promoted
|
|
|
227
242
|
return client_response
|
|
228
243
|
end
|
|
229
244
|
|
|
230
|
-
##
|
|
231
|
-
# Generate a log request for a subsequent call to send_log_request
|
|
232
|
-
# or for logging via alternative means.
|
|
233
|
-
def prepare_for_logging args, headers={}
|
|
234
|
-
args = Promoted::Ruby::Client::Util.translate_hash(args)
|
|
235
|
-
|
|
236
|
-
if !@enabled
|
|
237
|
-
return {
|
|
238
|
-
insertion: args[:full_insertion]
|
|
239
|
-
}
|
|
240
|
-
end
|
|
241
|
-
|
|
242
|
-
log_request_builder = RequestBuilder.new
|
|
243
|
-
|
|
244
|
-
# Note: This method expects as JSON (string keys) but internally, RequestBuilder
|
|
245
|
-
# transforms and works with symbol keys.
|
|
246
|
-
log_request_builder.set_request_params(args)
|
|
247
|
-
shadow_traffic_err = false
|
|
248
|
-
if @perform_checks
|
|
249
|
-
perform_common_checks! args
|
|
250
|
-
|
|
251
|
-
if @shadow_traffic_delivery_percent > 0 && args[:insertion_page_type] != Promoted::Ruby::Client::INSERTION_PAGING_TYPE['UNPAGED'] then
|
|
252
|
-
shadow_traffic_err = true
|
|
253
|
-
@logger.error(ShadowTrafficInsertionPageType.new) if @logger
|
|
254
|
-
end
|
|
255
|
-
end
|
|
256
|
-
|
|
257
|
-
log_request_builder.ensure_client_timestamp
|
|
258
|
-
|
|
259
|
-
if !shadow_traffic_err && should_send_as_shadow_traffic?
|
|
260
|
-
deliver_shadow_traffic args, headers
|
|
261
|
-
end
|
|
262
|
-
|
|
263
|
-
log_request_builder.log_request_params(
|
|
264
|
-
include_delivery_log: true,
|
|
265
|
-
exec_server: Promoted::Ruby::Client::EXECUTION_SERVER['SDK'])
|
|
266
|
-
end
|
|
267
|
-
|
|
268
245
|
##
|
|
269
246
|
# Sends a log request (previously created by a call to prepare_for_logging) to the metrics endpoint.
|
|
270
247
|
def send_log_request log_request_params, headers={}
|
|
@@ -281,7 +258,7 @@ module Promoted
|
|
|
281
258
|
##
|
|
282
259
|
# Creates response insertions for SDK-side delivery, when we don't get response insertions from Delivery API.
|
|
283
260
|
def build_sdk_response_insertions delivery_request_builder
|
|
284
|
-
response_insertions = @pager.apply_paging(delivery_request_builder.
|
|
261
|
+
response_insertions = @pager.apply_paging(delivery_request_builder.insertion, Promoted::Ruby::Client::INSERTION_PAGING_TYPE['UNPAGED'], delivery_request_builder.request[:paging])
|
|
285
262
|
delivery_request_builder.add_missing_insertion_ids! response_insertions
|
|
286
263
|
return response_insertions
|
|
287
264
|
end
|
|
@@ -358,7 +335,7 @@ module Promoted
|
|
|
358
335
|
delivery_request_params[:client_info][:traffic_type] = Promoted::Ruby::Client::TRAFFIC_TYPE['SHADOW']
|
|
359
336
|
|
|
360
337
|
begin
|
|
361
|
-
@pager.validate_paging(delivery_request_builder.
|
|
338
|
+
@pager.validate_paging(delivery_request_builder.insertion, delivery_request_builder.request[:paging])
|
|
362
339
|
rescue InvalidPagingError => err
|
|
363
340
|
# Invalid input, log and skip.
|
|
364
341
|
@logger.warn("Shadow traffic call failed with invalid paging #{err}") if @logger
|
|
@@ -370,6 +347,7 @@ module Promoted
|
|
|
370
347
|
response = nil
|
|
371
348
|
begin
|
|
372
349
|
response = send_request(delivery_request_params, @delivery_endpoint, @delivery_timeout_millis, @delivery_api_key, headers, @async_shadow_traffic)
|
|
350
|
+
@validator.validate_response!(response)
|
|
373
351
|
rescue StandardError => err
|
|
374
352
|
@logger.warn("Shadow traffic call failed with #{err}") if @logger
|
|
375
353
|
return
|
|
@@ -386,6 +364,7 @@ module Promoted
|
|
|
386
364
|
begin
|
|
387
365
|
@validator.check_that_log_ids_not_set!(req)
|
|
388
366
|
@validator.validate_metrics_request!(req)
|
|
367
|
+
@validator.check_that_content_ids_are_set!(req)
|
|
389
368
|
rescue StandardError => err
|
|
390
369
|
@logger.error(err) if @logger
|
|
391
370
|
raise
|
|
@@ -14,7 +14,9 @@ Gem::Specification.new do |spec|
|
|
|
14
14
|
spec.homepage = 'https://github.com/promotedai/promoted-ruby-client'
|
|
15
15
|
spec.license = 'MIT'
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
# Uncomment if you want to push to a custom host
|
|
18
|
+
# spec.metadata["allowed_push_host"] = "TODO: Set to 'http://mygemserver.com'"
|
|
19
|
+
|
|
18
20
|
spec.metadata["homepage_uri"] = spec.homepage
|
|
19
21
|
spec.metadata["source_code_uri"] = "https://github.com/promotedai/promoted-ruby-client"
|
|
20
22
|
spec.metadata["changelog_uri"] = "https://github.com/promotedai/promoted-ruby-client/blob/master/CHANGELOG.md"
|
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: 1.0.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- scottmcmaster
|
|
8
|
-
autorequire:
|
|
8
|
+
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2023-03-18 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: faraday
|
|
@@ -150,11 +150,10 @@ homepage: https://github.com/promotedai/promoted-ruby-client
|
|
|
150
150
|
licenses:
|
|
151
151
|
- MIT
|
|
152
152
|
metadata:
|
|
153
|
-
allowed_push_host: https://rubygems.org/
|
|
154
153
|
homepage_uri: https://github.com/promotedai/promoted-ruby-client
|
|
155
154
|
source_code_uri: https://github.com/promotedai/promoted-ruby-client
|
|
156
155
|
changelog_uri: https://github.com/promotedai/promoted-ruby-client/blob/master/CHANGELOG.md
|
|
157
|
-
post_install_message:
|
|
156
|
+
post_install_message:
|
|
158
157
|
rdoc_options: []
|
|
159
158
|
require_paths:
|
|
160
159
|
- lib
|
|
@@ -169,8 +168,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
169
168
|
- !ruby/object:Gem::Version
|
|
170
169
|
version: '0'
|
|
171
170
|
requirements: []
|
|
172
|
-
rubygems_version: 3.
|
|
173
|
-
signing_key:
|
|
171
|
+
rubygems_version: 3.3.11
|
|
172
|
+
signing_key:
|
|
174
173
|
specification_version: 4
|
|
175
174
|
summary: A Ruby Client to contact Promoted APIs.
|
|
176
175
|
test_files: []
|