promoted-ruby-client 1.0.1 → 2.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/Gemfile.lock +1 -1
- data/README.md +1 -1
- data/dev.md +7 -1
- data/lib/promoted/ruby/client/log_request_builder.rb +61 -0
- data/lib/promoted/ruby/client/pager.rb +8 -5
- data/lib/promoted/ruby/client/request_builder.rb +0 -82
- data/lib/promoted/ruby/client/util.rb +3 -3
- data/lib/promoted/ruby/client/version.rb +1 -1
- data/lib/promoted/ruby/client.rb +18 -26
- metadata +4 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 05e28ca6fd30469a610359aa335a16e57f936855fc2db54b8a134fa14a5b8119
|
|
4
|
+
data.tar.gz: 1a9761eef161f0fb6ff6fe34be49490e99b814bc977530ef1586cdcc52c33a48
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 171e24016958cd1319d0dce62de4a4f46e9571c40db7085745f0f7d967930947f3b1c6eda31793a98c827cc08837eb19f4a3e26f32a3bde9bb1a31a18d052f6b
|
|
7
|
+
data.tar.gz: 92589062b4f45c5e93589edd0ff8402027520b0d95c65e86138ec671e04f9d6604d7c3de3d8c58e1ecbf6e2c2f93ec9fe66f4e9208cda47fffee4c7c41514bc8
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
|
@@ -205,7 +205,7 @@ Field Name | Type | Optional? | Description
|
|
|
205
205
|
Output of ```deliver```, includes the insertions as well as a suitable ```LogRequest``` for forwarding to Metrics API.
|
|
206
206
|
Field Name | Type | Optional? | Description
|
|
207
207
|
---------- | ---- | --------- | -----------
|
|
208
|
-
```:insertion``` | [] of Insertion | No | The insertions, which are from Delivery API (when ```deliver``` was called, i.e. we weren't either only-log or part of an experiment) or the input insertions (when the other conditions don't hold).
|
|
208
|
+
```:insertion``` | [] of Insertion | No | The paged insertions, which are from Delivery API (when ```deliver``` was called, i.e. we weren't either only-log or part of an experiment) or the input insertions (when the other conditions don't hold).
|
|
209
209
|
```:log_request``` | LogRequest | Yes | A message suitable for logging to Metrics API via ```send_log_request```. If the call to ```deliver``` was made (i.e. the request was not part of the CONTROL arm of an experiment or marked to only log), ```:log_request``` will not be set, as you can assume logging was performed on the server-side by Promoted.
|
|
210
210
|
```:client_request_id``` | String | Yes | Client-generated request id sent to Delivery API and may be useful for logging and debugging.
|
|
211
211
|
```:execution_server``` | one of 'API' or 'SDK' | Yes | Indicates if response insertions on a delivery request came from the API or the SDK.
|
data/dev.md
CHANGED
|
@@ -1,8 +1,14 @@
|
|
|
1
|
+
# Run tests
|
|
2
|
+
|
|
3
|
+
```
|
|
4
|
+
bundle exec rspec
|
|
5
|
+
```
|
|
6
|
+
|
|
1
7
|
# Deploy
|
|
2
8
|
|
|
3
9
|
1. Update version number.
|
|
4
10
|
2. Get credentials for deployment from 1password.
|
|
5
11
|
3. Modify `promoted-ruby-client.gemspec`'s push block.
|
|
6
12
|
4. Run `gem build promoted-ruby-client.gemspec` to generate `gem`.
|
|
7
|
-
5. Run (using new output) `gem push promoted-ruby-client-
|
|
13
|
+
5. Run (using new output) `gem push promoted-ruby-client-2.0.1.gem`
|
|
8
14
|
6. Update README with new version.
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
module Promoted
|
|
2
|
+
module Ruby
|
|
3
|
+
module Client
|
|
4
|
+
class LogRequestBuilder
|
|
5
|
+
attr_reader :request, :response_insertions, :experiment
|
|
6
|
+
attr_accessor :request, :response_insertions, :experiment
|
|
7
|
+
|
|
8
|
+
def initialize args = {}
|
|
9
|
+
if args[:id_generator]
|
|
10
|
+
@id_generator = args[:id_generator]
|
|
11
|
+
else
|
|
12
|
+
@id_generator = IdGenerator.new
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def log_request(include_delivery_log:, exec_server:)
|
|
17
|
+
log_req = {
|
|
18
|
+
platform_id: @request[:platform_id],
|
|
19
|
+
user_info: @request[:user_info],
|
|
20
|
+
# For now, we'll just use the request timestamp.
|
|
21
|
+
timing: @request[:timing],
|
|
22
|
+
client_info: @request[:client_info],
|
|
23
|
+
device: @request[:device],
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
if @experiment
|
|
27
|
+
log_req[:cohort_membership] = [@experiment]
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# Log request allows for multiple requests but here we only send one.
|
|
31
|
+
if include_delivery_log
|
|
32
|
+
request[:request_id] = request[:request_id] || @id_generator.newID
|
|
33
|
+
# Remove redundant fields from `request` since they're already on the LogRequest.
|
|
34
|
+
stripped_request = @request.clone
|
|
35
|
+
stripped_request.delete(:platform_id)
|
|
36
|
+
stripped_request.delete(:user_info)
|
|
37
|
+
stripped_request.delete(:timing)
|
|
38
|
+
stripped_request.delete(:device)
|
|
39
|
+
stripped_request.delete(:client_info)
|
|
40
|
+
|
|
41
|
+
log_req[:delivery_log] = [{
|
|
42
|
+
execution: {
|
|
43
|
+
execution_server: exec_server,
|
|
44
|
+
server_version: Promoted::Ruby::Client::SERVER_VERSION
|
|
45
|
+
},
|
|
46
|
+
request: stripped_request,
|
|
47
|
+
response: {
|
|
48
|
+
insertion: @response_insertions
|
|
49
|
+
}
|
|
50
|
+
}]
|
|
51
|
+
end
|
|
52
|
+
log_req.clean!
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
require "promoted/ruby/client/constants"
|
|
60
|
+
require "promoted/ruby/client/extensions"
|
|
61
|
+
require "promoted/ruby/client/id_generator"
|
|
@@ -50,11 +50,14 @@ module Promoted
|
|
|
50
50
|
final_insertion_size = [size, insertions.length - index].min
|
|
51
51
|
insertion_page = Array.new(final_insertion_size)
|
|
52
52
|
0.upto(final_insertion_size - 1) {|i|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
53
|
+
request_insertion = insertions[index]
|
|
54
|
+
# Pager returns response insertions. Create a copy and fill in some of the fields.
|
|
55
|
+
response_insertion = Hash[]
|
|
56
|
+
response_insertion[:content_id] = request_insertion[:content_id]
|
|
57
|
+
response_insertion[:insertion_id] = request_insertion[:insertion_id]
|
|
58
|
+
# TODO - implement retrieval_start.
|
|
59
|
+
response_insertion[:position] = offset
|
|
60
|
+
insertion_page[i] = response_insertion
|
|
58
61
|
index = index + 1
|
|
59
62
|
offset = offset + 1
|
|
60
63
|
}
|
|
@@ -49,7 +49,6 @@ module Promoted
|
|
|
49
49
|
return @experiment
|
|
50
50
|
end
|
|
51
51
|
|
|
52
|
-
# Only used in delivery
|
|
53
52
|
def delivery_request_params
|
|
54
53
|
params = {
|
|
55
54
|
user_info: user_info,
|
|
@@ -70,93 +69,12 @@ module Promoted
|
|
|
70
69
|
params.clean!
|
|
71
70
|
end
|
|
72
71
|
|
|
73
|
-
# Only used in delivery
|
|
74
|
-
# Maps the response insertions to the full insertions and re-insert the properties bag
|
|
75
|
-
# to the responses.
|
|
76
|
-
def fill_details_from_response response_insertions
|
|
77
|
-
if !response_insertions then
|
|
78
|
-
response_insertions = []
|
|
79
|
-
end
|
|
80
|
-
|
|
81
|
-
props = @insertion.each_with_object({}) do |insertion, hash|
|
|
82
|
-
if insertion.has_key?(:properties)
|
|
83
|
-
# Don't add nil properties to response insertions.
|
|
84
|
-
hash[insertion[:content_id]] = insertion[:properties]
|
|
85
|
-
end
|
|
86
|
-
end
|
|
87
|
-
|
|
88
|
-
filled_in_copy = []
|
|
89
|
-
response_insertions.each do |resp_insertion|
|
|
90
|
-
copied_insertion = resp_insertion.clone
|
|
91
|
-
if copied_insertion.has_key?(:content_id) && props.has_key?(copied_insertion[:content_id])
|
|
92
|
-
copied_insertion[:properties] = props[resp_insertion[:content_id]]
|
|
93
|
-
end
|
|
94
|
-
filled_in_copy << copied_insertion
|
|
95
|
-
end
|
|
96
|
-
|
|
97
|
-
filled_in_copy
|
|
98
|
-
end
|
|
99
|
-
|
|
100
|
-
def log_request_params(include_delivery_log:, exec_server:)
|
|
101
|
-
params = {
|
|
102
|
-
user_info: user_info,
|
|
103
|
-
timing: timing,
|
|
104
|
-
client_info: merge_client_info_defaults,
|
|
105
|
-
device: @device,
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
if @experiment
|
|
109
|
-
params[:cohort_membership] = [@experiment]
|
|
110
|
-
end
|
|
111
|
-
|
|
112
|
-
# Log request allows for multiple requests but here we only send one.
|
|
113
|
-
if include_delivery_log
|
|
114
|
-
request[:request_id] = request[:request_id] || @id_generator.newID
|
|
115
|
-
|
|
116
|
-
params[:delivery_log] = [{
|
|
117
|
-
execution: {
|
|
118
|
-
execution_server: exec_server,
|
|
119
|
-
server_version: Promoted::Ruby::Client::SERVER_VERSION
|
|
120
|
-
},
|
|
121
|
-
request: request,
|
|
122
|
-
response: {
|
|
123
|
-
insertion: response_insertion
|
|
124
|
-
}
|
|
125
|
-
}]
|
|
126
|
-
|
|
127
|
-
add_missing_insertion_ids! params[:delivery_log][0][:response][:insertion]
|
|
128
|
-
end
|
|
129
|
-
|
|
130
|
-
params.clean!
|
|
131
|
-
end
|
|
132
|
-
|
|
133
72
|
def ensure_client_timestamp
|
|
134
73
|
if timing[:client_log_timestamp].nil?
|
|
135
74
|
timing[:client_log_timestamp] = (Time.now.to_f * 1000).to_i
|
|
136
75
|
end
|
|
137
76
|
end
|
|
138
77
|
|
|
139
|
-
def response_insertion
|
|
140
|
-
@response_insertions = []
|
|
141
|
-
paging = request[:paging] || {}
|
|
142
|
-
size = paging[:size] ? paging[:size].to_i : 0
|
|
143
|
-
if size <= 0
|
|
144
|
-
size = insertion.length()
|
|
145
|
-
end
|
|
146
|
-
offset = paging[:offset] ? paging[:offset].to_i : 0
|
|
147
|
-
|
|
148
|
-
insertion.each_with_index do |insertion_obj, index|
|
|
149
|
-
# TODO - this does not look performant.
|
|
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!
|
|
156
|
-
end
|
|
157
|
-
@response_insertions
|
|
158
|
-
end
|
|
159
|
-
|
|
160
78
|
def add_missing_insertion_ids! insertions
|
|
161
79
|
insertions.each do |insertion|
|
|
162
80
|
insertion[:insertion_id] = @id_generator.newID if not insertion[:insertion_id]
|
data/lib/promoted/ruby/client.rb
CHANGED
|
@@ -135,10 +135,10 @@ module Promoted
|
|
|
135
135
|
if @perform_checks
|
|
136
136
|
perform_common_checks!(args)
|
|
137
137
|
if !only_log && args[:insertion_page_type] == Promoted::Ruby::Client::INSERTION_PAGING_TYPE['PRE_PAGED'] then
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
138
|
+
err = DeliveryInsertionPageType.new
|
|
139
|
+
@logger.error(err) if @logger
|
|
140
|
+
raise err
|
|
141
|
+
end
|
|
142
142
|
|
|
143
143
|
if should_send_shadow_traffic && args[:insertion_page_type] != Promoted::Ruby::Client::INSERTION_PAGING_TYPE['UNPAGED'] then
|
|
144
144
|
should_send_shadow_traffic = false
|
|
@@ -177,23 +177,23 @@ module Promoted
|
|
|
177
177
|
if should_apply_treatment(cohort_membership_to_log)
|
|
178
178
|
# Call Delivery API to get insertions to use
|
|
179
179
|
delivery_request_params = delivery_request_builder.delivery_request_params
|
|
180
|
+
# Don't send shadow traffic if we've already tried normal traffic.
|
|
181
|
+
should_send_shadow_traffic = false
|
|
180
182
|
begin
|
|
181
183
|
response = send_request(delivery_request_params, @delivery_endpoint, @delivery_timeout_millis, @delivery_api_key, headers)
|
|
182
184
|
@validator.validate_response!(response)
|
|
185
|
+
raise ValidationError.new("Response shoul be a Hash") if !response.is_a?(Hash)
|
|
186
|
+
response_insertions = response && response[:insertion] || []
|
|
187
|
+
insertions_from_delivery = (response != nil && !deliver_err);
|
|
183
188
|
rescue StandardError => err
|
|
184
189
|
# Currently we don't propagate errors to the SDK caller, but rather default to returning
|
|
185
190
|
# the request insertions.
|
|
186
191
|
deliver_err = true
|
|
187
192
|
@logger.error("Error calling delivery: " + err.message) if @logger
|
|
188
193
|
end
|
|
189
|
-
should_send_shadow_traffic = false
|
|
190
194
|
else
|
|
191
195
|
should_send_shadow_traffic &&= @send_shadow_traffic_for_control
|
|
192
196
|
end
|
|
193
|
-
|
|
194
|
-
insertions_from_delivery = (response != nil && !deliver_err);
|
|
195
|
-
response_insertions = delivery_request_builder.fill_details_from_response(
|
|
196
|
-
response && response[:insertion] || [])
|
|
197
197
|
end
|
|
198
198
|
|
|
199
199
|
should_send_shadow_traffic &&= should_send_as_shadow_traffic?
|
|
@@ -202,33 +202,24 @@ module Promoted
|
|
|
202
202
|
deliver_shadow_traffic args, headers
|
|
203
203
|
end
|
|
204
204
|
|
|
205
|
-
request_to_log = nil
|
|
206
205
|
if !insertions_from_delivery then
|
|
207
|
-
request_to_log = delivery_request_builder.request
|
|
208
206
|
response_insertions = build_sdk_response_insertions(delivery_request_builder)
|
|
209
207
|
end
|
|
210
208
|
|
|
211
209
|
log_req = nil
|
|
212
210
|
exec_server = (insertions_from_delivery ? Promoted::Ruby::Client::EXECUTION_SERVER['API'] : Promoted::Ruby::Client::EXECUTION_SERVER['SDK'])
|
|
213
|
-
|
|
214
|
-
# We only return a log request if there's a request or cohort to log.
|
|
215
|
-
if request_to_log || cohort_membership_to_log
|
|
216
|
-
log_request_builder = RequestBuilder.new
|
|
217
|
-
log_request = {
|
|
218
|
-
:insertion => response_insertions,
|
|
219
|
-
:experiment => cohort_membership_to_log,
|
|
220
|
-
:request => request_to_log
|
|
221
|
-
}
|
|
222
|
-
log_request_builder.set_request_params(log_request)
|
|
223
211
|
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
log_request_builder
|
|
227
|
-
|
|
212
|
+
# We only return a log request if there's a request or cohort to log.
|
|
213
|
+
if !insertions_from_delivery || cohort_membership_to_log
|
|
214
|
+
log_request_builder = LogRequestBuilder.new
|
|
215
|
+
# TODO - make this more efficient.
|
|
216
|
+
log_request_builder.request = delivery_request_builder.delivery_request_params
|
|
217
|
+
log_request_builder.response_insertions = response_insertions
|
|
218
|
+
log_request_builder.experiment = cohort_membership_to_log
|
|
228
219
|
|
|
229
220
|
# On a successful delivery request, we don't log the insertions
|
|
230
221
|
# or the request since they are logged on the server-side.
|
|
231
|
-
log_req = log_request_builder.
|
|
222
|
+
log_req = log_request_builder.log_request(
|
|
232
223
|
include_delivery_log: !insertions_from_delivery,
|
|
233
224
|
exec_server: exec_server)
|
|
234
225
|
end
|
|
@@ -386,6 +377,7 @@ module Promoted
|
|
|
386
377
|
end
|
|
387
378
|
|
|
388
379
|
# dependent /libs
|
|
380
|
+
require "promoted/ruby/client/log_request_builder"
|
|
389
381
|
require "promoted/ruby/client/request_builder"
|
|
390
382
|
require "promoted/ruby/client/pager"
|
|
391
383
|
require "promoted/ruby/client/sampler"
|
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:
|
|
4
|
+
version: 2.0.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- scottmcmaster
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2023-03-
|
|
11
|
+
date: 2023-03-27 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: faraday
|
|
@@ -139,6 +139,7 @@ files:
|
|
|
139
139
|
- lib/promoted/ruby/client/extensions.rb
|
|
140
140
|
- lib/promoted/ruby/client/faraday_http_client.rb
|
|
141
141
|
- lib/promoted/ruby/client/id_generator.rb
|
|
142
|
+
- lib/promoted/ruby/client/log_request_builder.rb
|
|
142
143
|
- lib/promoted/ruby/client/pager.rb
|
|
143
144
|
- lib/promoted/ruby/client/request_builder.rb
|
|
144
145
|
- lib/promoted/ruby/client/sampler.rb
|
|
@@ -168,7 +169,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
168
169
|
- !ruby/object:Gem::Version
|
|
169
170
|
version: '0'
|
|
170
171
|
requirements: []
|
|
171
|
-
rubygems_version: 3.
|
|
172
|
+
rubygems_version: 3.4.9
|
|
172
173
|
signing_key:
|
|
173
174
|
specification_version: 4
|
|
174
175
|
summary: A Ruby Client to contact Promoted APIs.
|