promoted-ruby-client 3.0.0 → 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: ffd08d1b6e14b721172d2e30680541f1d087d14f7cdfe63dc96b60ada84b5b1a
4
- data.tar.gz: d21fa553ef8e746c642605bb2de051d4bdc9901b5837c1db6f1ca11fe358fa98
3
+ metadata.gz: a4d336aef96b116acbe2e611279e9ccefe5efce88063d5c530fb669b32383d10
4
+ data.tar.gz: 6df512d099b5a5b9414b2672847585db2118825b87c178b923da26ba2cb610e8
5
5
  SHA512:
6
- metadata.gz: bf16053b5bef1560caf7e9a5eaf01b62dd4484d40069801310d4cc8b7eb0fdce91eb072ee4c8a1146188b5fc74a168b2769623379dfd8df2a9f493d1e214a012
7
- data.tar.gz: f814b279bd1585402a381e8269c9c4664964381702fb5fb597845990ace9e56fdb5b8e0d24d8b2d4f3373523f764798092bcb5c324f2ca90d173b4008035993f
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.
@@ -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
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-3.0.0.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
@@ -1,7 +1,7 @@
1
1
  module Promoted
2
2
  module Ruby
3
3
  module Client
4
- VERSION = "3.0.0"
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: 3.0.0
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-09-08 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