promoted-ruby-client 2.0.2 → 4.0.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: 11ce5ae07d4a391a8e052befa249acf77a5e1c2b8bd27af1cc5abb24d011551f
4
- data.tar.gz: b2526b7a4b3f2940283c27930a85bcd8e9b469e63c3276271e1ef1d9ffafb096
3
+ metadata.gz: a4d336aef96b116acbe2e611279e9ccefe5efce88063d5c530fb669b32383d10
4
+ data.tar.gz: 6df512d099b5a5b9414b2672847585db2118825b87c178b923da26ba2cb610e8
5
5
  SHA512:
6
- metadata.gz: ca464c620e04043e7998bc12d9792931fd220b00d8fcfc9a777149a27c6b5b42710409ce48bf43787da346743837f6934df11ce56070bb725ba021c6de1c1908
7
- data.tar.gz: 0c3a880b7aa8b8b16523cbe60f75af5ef89849ce5de16a7d19a907aad1429e27a873136d95194fa3b21c4fdc01b663087000e10ae05cb713b638f7b8cbb980b0
6
+ metadata.gz: 7375f08d88303d6de8eefaf3a4b7e2b80333f15e8b709781c4884aee54d84c9d64b6bdc834c4a5c53f1f426a04a5aed9752cc7ceba78d6015f100d7ee6096e0c
7
+ data.tar.gz: 2cdff05db0a989331ca56e0f18716f53e635ea7d000d685275693b21445a313763e2001827b201ec2863173eb52f54744b50177f824ae7a0d44a85f975105e5e
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- promoted-ruby-client (2.0.2)
4
+ promoted-ruby-client (4.0.0)
5
5
  concurrent-ruby (~> 1)
6
6
  faraday (>= 0.9.0)
7
7
  faraday_middleware (>= 0.9.0)
@@ -52,13 +52,12 @@ GEM
52
52
  rexml
53
53
  kramdown-parser-gfm (1.1.0)
54
54
  kramdown (~> 2.0)
55
- language_server-protocol (3.17.0.3)
56
55
  multipart-post (2.3.0)
57
56
  net-http-persistent (4.0.2)
58
57
  connection_pool (~> 2.2)
59
- nokogiri (1.15.2-arm64-darwin)
58
+ nokogiri (1.15.4-arm64-darwin)
60
59
  racc (~> 1.4)
61
- nokogiri (1.15.2-x86_64-linux)
60
+ nokogiri (1.15.4-x86_64-linux)
62
61
  racc (~> 1.4)
63
62
  parallel (1.23.0)
64
63
  parser (3.2.2.3)
@@ -85,11 +84,10 @@ GEM
85
84
  diff-lcs (>= 1.2.0, < 2.0)
86
85
  rspec-support (~> 3.12.0)
87
86
  rspec-support (3.12.1)
88
- rubocop (1.53.1)
87
+ rubocop (1.50.2)
89
88
  json (~> 2.3)
90
- language_server-protocol (>= 3.17.0)
91
89
  parallel (~> 1.10)
92
- parser (>= 3.2.2.3)
90
+ parser (>= 3.2.0.0)
93
91
  rainbow (>= 2.2.2, < 4.0)
94
92
  regexp_parser (>= 1.8, < 3.0)
95
93
  rexml (>= 3.2.5, < 4.0)
@@ -142,4 +140,4 @@ DEPENDENCIES
142
140
  solargraph
143
141
 
144
142
  BUNDLED WITH
145
- 2.4.9
143
+ 2.4.19
data/README.md CHANGED
@@ -20,7 +20,7 @@ HTTP client for calling Promoted.
20
20
  ### [Net::HTTP::Persistent](https://github.com/drbrain/net-http-persistent)
21
21
  Faraday binding (provides connection pool support)
22
22
  ### [Concurrent Ruby](https://github.com/ruby-concurrency/concurrent-ruby)
23
- Provides a thread pool for making shadow traffic requests to Delivery API in the background on a subset of calls to ```prepare_for_logging```
23
+ Provides a thread pool for making shadow traffic requests to Delivery API in the background on a subset of calls to ```deliver```
24
24
  ## Creating a Client
25
25
  ```rb
26
26
  client = Promoted::Ruby::Client::PromotedClient.new
@@ -48,7 +48,7 @@ Name | Type | Description
48
48
  ```:metrics_timeout_millis``` | Number | Timeout on the Metrics API call. Defaults to 3000.
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
- ```: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).
51
+ ```:shadow_traffic_delivery_percent``` | Number between 0 and 1 | % of ```deliver``` traffic that gets directed to Delivery API as "shadow traffic". Defaults to 0 (no shadow traffic).
52
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.
53
53
  ```:default_request_headers``` | Hash | Additional headers to send on the request beyond ```x-api-key```. Defaults to {}
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.
@@ -63,7 +63,7 @@ Basic information about the request user.
63
63
  Field Name | Type | Optional? | Description
64
64
  ---------- | ---- | --------- | -----------
65
65
  ```:user_id``` | String | Yes | The platform user id, cleared from Promoted logs.
66
- ```: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
+ ```:anon_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.
67
67
  ```:is_internal_user``` | Boolean | Yes | If this user is a test user or not, defaults to false.
68
68
 
69
69
  ---
@@ -169,7 +169,14 @@ Field Name | Type | Optional? | Description
169
169
  ```:browser``` | Browser | Yes | Browser information
170
170
  ---
171
171
  ### Paging
172
- #### TODO
172
+ Paging parameters.
173
+
174
+ ```DeliveryRequest.retrieval_insertion_offset``` also impacts paging. That field indicate the offset of the retrieved insertions that are passed into ```Request.insertion```. See [detailed documentation on paging and ```retrieval_insertion_offset```](https://docs.promoted.ai/docs/ranking-requests#sending-even-more-request-insertions).
175
+
176
+ Field Name | Type | Optional? | Description
177
+ ---------- | ---- | --------- | -----------
178
+ ```:offset``` | Integer | Yes | The 0-based, starting index for the response page. This should be the global position.
179
+ ```:size``` | Integer | Yes | The number of items to return in a response page.
173
180
  ---
174
181
  ### Request
175
182
  A request for content insertions.
@@ -179,7 +186,7 @@ Field Name | Type | Optional? | Description
179
186
  ```:request_id``` | String | Yes | Generated by the SDK when needed (*do not set*)
180
187
  ```:use_case``` | String | Yes | One of the use case values, i.e. 'FEED' (see [constants.rb](https://github.com/promotedai/promoted-ruby-client/blob/main/lib/promoted/ruby/client/constants.rb)).
181
188
  ```:properties``` | Properties | Yes | Any additional custom properties to associate.
182
- ```:paging``` | Paging | Yes | Paging parameters (see TODO)
189
+ ```:paging``` | Paging | Yes | Paging parameters
183
190
  ```:device``` | Device | Yes | Device information (as available)
184
191
  ---
185
192
 
@@ -190,15 +197,12 @@ Field Name | Type | Optional? | Description
190
197
  ```:experiment``` | CohortMembership | Yes | A cohort to evaluation in experimentation.
191
198
  ```:request``` | Request | No | The underlying request for content.
192
199
  ```:only_log``` | Boolean | Yes | Defaults to false. Set to true to override whether Delivery API is called for this request.
200
+ ```:retrieval_insertion_offset``` | Integer | Yes | The index of the retrieved insertions set on ```Request.insertion``` list. If just sending the top-N from your retrieval, this is ```0```. If this is the next batch (e.g. ```500``` to ```999```), then the value is ```500```. This can be used to send multiple groups of retrieved insertions. This interacts with the ```Paging``` fields. [More detailed documentation on paging](https://docs.promoted.ai/docs/ranking-requests#sending-even-more-request-insertions).
193
201
  ---
194
202
 
195
203
  ### LogRequest
196
204
 
197
- Output of ```prepare_for_logging``` as well as an ouput of an SDK call to ```deliver```, input to ```send_log_request``` to log to Promoted
198
- Field Name | Type | Optional? | Description
199
- ---------- | ---- | --------- | -----------
200
- ```:request``` | Request | No | The underlying request for content to log.
201
- ```:insertion``` | [] of Insertion | No | The insertions, which are either the original request insertions or the insertions resulting from a call to ```deliver``` if such call occurred.
205
+ A log object that is sent as a RPC request to Promoted's Metrics API log endpoint. This is outputted from the ```deliver``` SDK call. Callers need to either input it into the ```send_log_request``` method or send it to the Metrics API directly. Clients should avoid manipulating this object directly.
202
206
  ---
203
207
 
204
208
  ### ClientResponse
@@ -214,18 +218,12 @@ Field Name | Type | Optional? | Description
214
218
  ### PromotedClient
215
219
  Method | Input | Output | Description
216
220
  ------ | ----- | ------ | -----------
217
- ```prepare_for_logging``` | MetricsRequest | LogRequest | Builds a request suitable for logging locally and/or to Promoted, either via a subsequent call to ```send_log_request``` in the SDK client or by using this structure to make the call yourself. Optionally, based on client configuration may send a random subset of requests to Delivery API as shadow traffic for integration purposes.
218
221
  ```send_log_request``` | LogRequest | n/a | Forwards a LogRequest to Promoted using an HTTP client.
219
- ```deliver``` | DeliveryRequest | ClientResponse | Makes a request (subject to experimentation) to Delivery API for insertions, which are then returned along with a LogRequest.
222
+ ```deliver``` | DeliveryRequest | ClientResponse | Depending on flags, either (1) makes a request (subject to experimentation) to Delivery API for insertions, which are then returned along with a LogRequest or (2) implements SDK-side paging and prepares log records that can be logged to Promoted using ```send_log_request``` or by using this structure to make the call yourself. Optionally, based on client configuration may send a random subset of requests to Delivery API as shadow traffic for integration purposes.
220
223
  ```close``` | n/a | n/a | Closes down the client at shutdown, currently this is just to drain the thread pool that handles shadow traffic.
221
224
  ---
222
225
 
223
226
  ## Metrics API
224
- ### Pagination
225
-
226
- The `prepare_for_logging` call assumes the client has already handled pagination. It needs a `Request.paging.offset` to be passed in for the number of items deep that the page is.
227
- TODO: Needs more details.
228
-
229
227
  ### Expected flow for Metrics logging
230
228
 
231
229
  ```rb
@@ -270,7 +268,7 @@ insertions = products.map { |product|
270
268
  # Form a MetricsRequest
271
269
  metrics_request = {
272
270
  :request => {
273
- :user_info => { :user_id => "912", :log_user_id => "912191"},
271
+ :user_info => { :user_id => "912", :anon_user_id => "912191"},
274
272
  :use_case => "FEED",
275
273
  :paging => {
276
274
  :offset => 0,
@@ -306,7 +304,7 @@ client.send_log_request(client_response[:log_request]) if client_response[:log_r
306
304
  # Form a DeliveryRequest
307
305
  delivery_request = {
308
306
  :request => {
309
- :user_info => { :user_id => "912", :log_user_id => "912191"},
307
+ :user_info => { :user_id => "912", :anon_user_id => "912191"},
310
308
  :use_case => "FEED",
311
309
  :paging => {
312
310
  :offset => 0,
data/dev.md CHANGED
@@ -10,5 +10,5 @@ bundle exec rspec
10
10
  2. Get credentials for deployment from 1password.
11
11
  3. Modify `promoted-ruby-client.gemspec`'s push block.
12
12
  4. Run `gem build promoted-ruby-client.gemspec` to generate `gem`.
13
- 5. Run (using new output) `gem push promoted-ruby-client-2.0.2.gem`
14
- 6. Update README with new version.
13
+ 5. Run `bundle exec rspec`. This updates `Gemfile.lock`.
14
+ 6. Run (using new output) `gem push promoted-ruby-client-4.0.0.gem`
@@ -14,9 +14,6 @@ module Promoted
14
14
  'SELLER_CONTENT'=> 'SELLER_CONTENT',
15
15
  'DISCOVER'=> 'DISCOVER'}
16
16
 
17
- INSERTION_PAGING_TYPE = {'UNPAGED' => 'UNPAGED',
18
- 'PRE_PAGED' => 'PRE_PAGED'}
19
-
20
17
  COHORT_ARM = {'UNKNOWN_GROUP' => 'UNKNOWN_GROUP',
21
18
  'CONTROL' => 'CONTROL',
22
19
  'TREATMENT' => 'TREATMENT',
@@ -1,18 +1,6 @@
1
1
  module Promoted
2
2
  module Ruby
3
3
  module Client
4
- class ShadowTrafficInsertionPageType < StandardError
5
- def message
6
- 'Insertions must be unpaged when shadow traffic is on'
7
- end
8
- end
9
-
10
- class DeliveryInsertionPageType < StandardError
11
- def message
12
- 'Delivery insertions must be unpaged'
13
- end
14
- end
15
-
16
4
  class EndpointError < StandardError
17
5
  attr_reader :cause
18
6
  def initialize(cause)
@@ -11,15 +11,21 @@ module Promoted
11
11
  end
12
12
 
13
13
  class Pager
14
- def validate_paging(insertions, paging)
15
- if paging && paging[:offset] && paging[:offset] >= insertions.length
16
- raise InvalidPagingError.new("Invalid page offset (insertion size #{insertions.length}, offset #{paging[:offset]})", [])
14
+ def validate_paging(insertions, retrieval_insertion_offset, paging)
15
+ if paging && paging[:offset]
16
+ offset = [0, paging[:offset]].max
17
+ if offset >= insertions.length
18
+ raise InvalidPagingError.new("Invalid page offset (insertion size #{insertions.length}, offset #{offset})", [])
19
+ end
20
+ if offset < retrieval_insertion_offset
21
+ raise InvalidPagingError.new("Invalid page offset (retrieval_insertion_offset #{retrieval_insertion_offset}, offset #{offset})", [])
22
+ end
17
23
  end
18
24
  end
19
25
 
20
- def apply_paging(insertions, insertion_page_type, paging = nil)
26
+ def apply_paging(insertions, retrieval_insertion_offset, paging = nil)
21
27
  begin
22
- validate_paging(insertions, paging)
28
+ validate_paging(insertions, retrieval_insertion_offset, paging)
23
29
  rescue InvalidPagingError => err
24
30
  # This is invalid input, stop it before it goes to the server.
25
31
  return err.default_insertions_page
@@ -33,14 +39,8 @@ module Promoted
33
39
  end
34
40
 
35
41
  offset = [0, paging[:offset]].max
36
-
37
- index = offset
38
- if insertion_page_type == Promoted::Ruby::Client::INSERTION_PAGING_TYPE['PRE_PAGED']
39
- # When insertions are pre-paged, we don't use offset to
40
- # window into the provided insertions, although we do use it when
41
- # assigning positions.
42
- index = 0
43
- end
42
+ retrieval_insertion_offset = [0, retrieval_insertion_offset].max
43
+ index = [0, offset - retrieval_insertion_offset].max
44
44
 
45
45
  size = paging[:size]
46
46
  if size <= 0
@@ -27,7 +27,7 @@ module Promoted
27
27
  @view_id = request[:view_id]
28
28
  @use_case = Promoted::Ruby::Client::USE_CASES[request[:use_case]] || Promoted::Ruby::Client::USE_CASES['UNKNOWN_USE_CASE']
29
29
  @insertion = request[:insertion] || []
30
- @user_info = request[:user_info] || { :user_id => nil, :log_user_id => nil}
30
+ @user_info = request[:user_info] || { :user_id => nil, :anon_user_id => nil}
31
31
  @timing = request[:timing] || { :client_log_timestamp => (Time.now.to_f * 1000).to_i }
32
32
 
33
33
  # If the user didn't create a client request id, we do it for them.
@@ -12,7 +12,7 @@ module Promoted
12
12
  :type => String
13
13
  },
14
14
  {
15
- :name => :log_user_id,
15
+ :name => :anon_user_id,
16
16
  :type => String
17
17
  },
18
18
  {
@@ -1,7 +1,7 @@
1
1
  module Promoted
2
2
  module Ruby
3
3
  module Client
4
- VERSION = "2.0.2"
4
+ VERSION = "4.0.0"
5
5
  SERVER_VERSION = "rb." + VERSION
6
6
  end
7
7
  end
@@ -54,6 +54,7 @@ module Promoted
54
54
 
55
55
  @sampler = Sampler.new
56
56
  @pager = Pager.new
57
+ @retrieval_insertion_offset = params[:retrieval_insertion_offset] || 0
57
58
 
58
59
  # HTTP Client creation
59
60
  @delivery_endpoint = params[:delivery_endpoint] || DEFAULT_DELIVERY_ENDPOINT
@@ -119,7 +120,7 @@ module Promoted
119
120
  # Respect the enabled state
120
121
  if !@enabled
121
122
  return {
122
- insertion: @pager.apply_paging(args[:request][:insertion], Promoted::Ruby::Client::INSERTION_PAGING_TYPE['UNPAGED'], args[:request][:paging])
123
+ insertion: @pager.apply_paging(args[:request][:insertion], @retrieval_insertion_offset, args[:request][:paging])
123
124
  # No log request returned when disabled
124
125
  }
125
126
  end
@@ -134,16 +135,6 @@ module Promoted
134
135
  # perform_checks raises errors.
135
136
  if @perform_checks
136
137
  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
142
-
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
146
- end
147
138
  end
148
139
 
149
140
  delivery_request_builder.ensure_client_timestamp
@@ -161,7 +152,7 @@ module Promoted
161
152
  end
162
153
 
163
154
  begin
164
- @pager.validate_paging(delivery_request_builder.insertion, delivery_request_builder.request[:paging])
155
+ @pager.validate_paging(delivery_request_builder.insertion, @retrieval_insertion_offset, delivery_request_builder.request[:paging])
165
156
  rescue InvalidPagingError => err
166
157
  # Invalid input, log and do SDK-side delivery.
167
158
  @logger.warn(err) if @logger
@@ -234,7 +225,7 @@ module Promoted
234
225
  end
235
226
 
236
227
  ##
237
- # Sends a log request (previously created by a call to prepare_for_logging) to the metrics endpoint.
228
+ # Sends a log request to the metrics endpoint.
238
229
  def send_log_request log_request_params, headers={}
239
230
  begin
240
231
  send_request(log_request_params, @metrics_endpoint, @metrics_timeout_millis, @metrics_api_key, headers)
@@ -249,7 +240,7 @@ module Promoted
249
240
  ##
250
241
  # Creates response insertions for SDK-side delivery, when we don't get response insertions from Delivery API.
251
242
  def build_sdk_response_insertions delivery_request_builder
252
- response_insertions = @pager.apply_paging(delivery_request_builder.insertion, Promoted::Ruby::Client::INSERTION_PAGING_TYPE['UNPAGED'], delivery_request_builder.request[:paging])
243
+ response_insertions = @pager.apply_paging(delivery_request_builder.insertion, @retrieval_insertion_offset, delivery_request_builder.request[:paging])
253
244
  delivery_request_builder.add_missing_insertion_ids! response_insertions
254
245
  return response_insertions
255
246
  end
@@ -317,7 +308,7 @@ module Promoted
317
308
 
318
309
  # Delivers shadow traffic from the given metrics args.
319
310
  # Assumes that the args have already been normalized since this
320
- # method should only be called from inside prepare_for_logging.
311
+ # method should only be called from inside deliver.
321
312
  def deliver_shadow_traffic args, headers
322
313
  delivery_request_builder = RequestBuilder.new
323
314
  delivery_request_builder.set_request_params args
@@ -326,7 +317,7 @@ module Promoted
326
317
  delivery_request_params[:client_info][:traffic_type] = Promoted::Ruby::Client::TRAFFIC_TYPE['SHADOW']
327
318
 
328
319
  begin
329
- @pager.validate_paging(delivery_request_builder.insertion, delivery_request_builder.request[:paging])
320
+ @pager.validate_paging(delivery_request_builder.insertion, @retrieval_insertion_offset, delivery_request_builder.request[:paging])
330
321
  rescue InvalidPagingError => err
331
322
  # Invalid input, log and skip.
332
323
  @logger.warn("Shadow traffic call failed with invalid paging #{err}") if @logger
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: 2.0.2
4
+ version: 4.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - scottmcmaster
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-06-30 00:00:00.000000000 Z
11
+ date: 2023-09-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: faraday