promoted-ruby-client 0.1.15 → 0.1.16

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: 99ee2c76dc1547104c6e40f5b05c1b7897fb609108d3009c686236ef5646f33b
4
- data.tar.gz: ff7dc6ed3901dac8112564687353c4942352b044d7b158ce2e9bd554843d777a
3
+ metadata.gz: a2c2ac1232cfaf7a98ca948a7949a420a6ab311c4b54d92ea8098e8b830e931b
4
+ data.tar.gz: 9ae8796dc993ecc11e01f1980a2200a7ee10dedb8287504a2bafcebec2f50105
5
5
  SHA512:
6
- metadata.gz: f7d4ab79296c610db92af6ba93d86023f254fef6d59753e991df0915b028b303a505e11cdce623345f1bc78414f30ecd72f8c237e3f2eb87a93f7c4b331ae690
7
- data.tar.gz: b612ddec96289bffe5b6eb2e9dff2b58f103d2008d53e8ff91069f2b6b13d24a179a25fbbe99315ea29b69cf227ad862da1eeb6204a05a288ab6a6caa0f23c3b
6
+ metadata.gz: d3df3068c668514c3666435fc1a4b25216223258fd305ba69e4cebf333f5026ff008f868a4bd7f3a15e748bd9b00ddb6dfbb9e0c0de7c72a9ed06ad4a175ddbe
7
+ data.tar.gz: 7adb59ff3806736008764d32a51176e1a064547259c8f4d7c9d800b4737e688d00b25593c07e5b2ecffc05daad1795830d17efb3f66284d6fc8f02b5045dd1f8
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- promoted-ruby-client (0.1.15)
4
+ promoted-ruby-client (0.1.16)
5
5
  concurrent-ruby (~> 1)
6
6
  faraday (>= 0.9.0)
7
7
  faraday_middleware (>= 0.9.0)
data/README.md CHANGED
@@ -17,6 +17,8 @@ More information at [http://www.promoted.ai](http://www.promoted.ai)
17
17
 
18
18
  ### [Faraday](https://github.com/lostisland/faraday)
19
19
  HTTP client for calling Promoted.
20
+ ### [Net::HTTP::Persistent](https://github.com/drbrain/net-http-persistent)
21
+ Faraday binding (provides connection pool support)
20
22
  ### [Concurrent Ruby](https://github.com/ruby-concurrency/concurrent-ruby)
21
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```
22
24
  ## Creating a Client
@@ -50,6 +52,7 @@ Name | Type | Description
50
52
  ```:default_request_headers``` | Hash | Additional headers to send on the request beyond ```x-api-key```. Defaults to {}
51
53
  ```: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.
52
54
  ```: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.
55
+ ```: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.
53
56
 
54
57
  ## Data Types
55
58
 
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.15.gem`
7
+ 5. Run (using new output) `gem push promoted-ruby-client-0.1.16.gem`
8
8
  6. Update README with new version.
@@ -73,7 +73,7 @@ module Promoted
73
73
  @delivery_timeout_millis = params[:delivery_timeout_millis] || DEFAULT_DELIVERY_TIMEOUT_MILLIS
74
74
  @metrics_timeout_millis = params[:metrics_timeout_millis] || DEFAULT_METRICS_TIMEOUT_MILLIS
75
75
 
76
- @http_client = FaradayHTTPClient.new
76
+ @http_client = FaradayHTTPClient.new(@logger)
77
77
  @validator = Promoted::Ruby::Client::Validator.new
78
78
 
79
79
  @async_shadow_traffic = true
@@ -97,6 +97,10 @@ module Promoted
97
97
  if params[:enabled] != nil
98
98
  @enabled = params[:enabled] || false
99
99
  end
100
+
101
+ if params[:warmup]
102
+ do_warmup
103
+ end
100
104
  end
101
105
 
102
106
  ##
@@ -109,7 +113,7 @@ module Promoted
109
113
  end
110
114
 
111
115
  ##
112
- # Make a delivery request.
116
+ # Make a delivery request. If @perform_checks is set, input validation will occur and possibly raise errors.
113
117
  def deliver args, headers={}
114
118
  args = Promoted::Ruby::Client::Util.translate_args(args)
115
119
 
@@ -124,7 +128,16 @@ module Promoted
124
128
  delivery_request_builder = RequestBuilder.new
125
129
  delivery_request_builder.set_request_params(args)
126
130
 
127
- perform_common_checks!(args) if @perform_checks
131
+ # perform_checks raises errors.
132
+ if @perform_checks
133
+ perform_common_checks!(args)
134
+
135
+ if args[:insertion_page_type] == Promoted::Ruby::Client::INSERTION_PAGING_TYPE['PRE_PAGED'] then
136
+ err = DeliveryInsertionPageType.new
137
+ @logger.error(err) if @logger
138
+ raise err
139
+ end
140
+ end
128
141
 
129
142
  delivery_request_builder.ensure_client_timestamp
130
143
 
@@ -135,10 +148,15 @@ module Promoted
135
148
  only_log = delivery_request_builder.only_log != nil ? delivery_request_builder.only_log : @default_only_log
136
149
  deliver_err = false
137
150
 
138
- if !@pager.validate_paging(delivery_request_builder.full_insertion, delivery_request_builder.request[:paging])
151
+ begin
152
+ @pager.validate_paging(delivery_request_builder.full_insertion, delivery_request_builder.request[:paging])
153
+ rescue InvalidPagingError => err
139
154
  # Invalid input, log and do SDK-side delivery.
140
- @logger.warn("Invalid paging parameters") if @logger
141
- only_log = true
155
+ @logger.warn(err) if @logger
156
+ return {
157
+ insertion: err.default_insertions_page
158
+ # No log request returned when no response insertions due to invalid paging
159
+ }
142
160
  end
143
161
 
144
162
  if !only_log
@@ -248,6 +266,22 @@ module Promoted
248
266
 
249
267
  private
250
268
 
269
+ def do_warmup
270
+ if !@delivery_endpoint
271
+ # Warmup only supported when delivery is enabled.
272
+ return
273
+ end
274
+
275
+ warmup_url = @delivery_endpoint.reverse.sub("/deliver".reverse, "/healthz".reverse).reverse
276
+ @logger.info("Warming up at #{warmup_url}") if @logger
277
+ 1.upto(20) do
278
+ resp = @http_client.get(warmup_url)
279
+ if resp != "ok"
280
+ @logger.warn("Got a failure warming up") if @logger
281
+ end
282
+ end
283
+ end
284
+
251
285
  def send_request payload, endpoint, timeout_millis, api_key, headers={}, send_async=false
252
286
  resp = nil
253
287
 
@@ -305,8 +339,9 @@ module Promoted
305
339
 
306
340
  # Call Delivery API and log/ignore errors.
307
341
  start_time = Time.now
342
+ response = nil
308
343
  begin
309
- send_request(delivery_request_params, @delivery_endpoint, @delivery_timeout_millis, @delivery_api_key, headers, @async_shadow_traffic)
344
+ response = send_request(delivery_request_params, @delivery_endpoint, @delivery_timeout_millis, @delivery_api_key, headers, @async_shadow_traffic)
310
345
  rescue StandardError => err
311
346
  @logger.warn("Shadow traffic call failed with #{err}") if @logger
312
347
  return
@@ -314,7 +349,8 @@ module Promoted
314
349
 
315
350
  if !@async_shadow_traffic
316
351
  ellapsed_time = Time.now - start_time
317
- @logger.info("Shadow traffic call completed in #{ellapsed_time.to_f * 1000} ms") if @logger
352
+ insertions = response ? response[:insertion] : []
353
+ @logger.info("Shadow traffic call completed in #{ellapsed_time.to_f * 1000} ms with #{insertions.length} insertions") if @logger
318
354
  end
319
355
  end
320
356
 
@@ -7,6 +7,12 @@ module Promoted
7
7
  end
8
8
  end
9
9
 
10
+ class DeliveryInsertionPageType < StandardError
11
+ def message
12
+ 'Delivery insertions must be unpaged'
13
+ end
14
+ end
15
+
10
16
  class EndpointError < StandardError
11
17
  attr_reader :cause
12
18
  def initialize(cause)
@@ -6,10 +6,13 @@ module Promoted
6
6
  module Client
7
7
  class FaradayHTTPClient
8
8
 
9
- def initialize
9
+ def initialize(logger = nil)
10
10
  @conn = Faraday.new do |f|
11
11
  f.request :json
12
12
  f.request :retry, max: 3
13
+ if logger
14
+ f.response :logger, logger, { headers: false, bodies: true, log_level: :debug }
15
+ end
13
16
  f.use Faraday::Response::RaiseError # raises on 4xx and 5xx responses
14
17
  f.adapter :net_http_persistent
15
18
  end
@@ -30,6 +33,10 @@ module Promoted
30
33
  response.body
31
34
  end
32
35
  end
36
+
37
+ def get(endpoint)
38
+ @conn.get(endpoint).body
39
+ end
33
40
  end
34
41
  end
35
42
  end
@@ -1,18 +1,28 @@
1
1
  module Promoted
2
2
  module Ruby
3
3
  module Client
4
+ class InvalidPagingError < StandardError
5
+ attr_reader :default_insertions_page
6
+
7
+ def initialize(message, default_insertions_page)
8
+ super(message)
9
+ @default_insertions_page = default_insertions_page
10
+ end
11
+ end
12
+
4
13
  class Pager
5
14
  def validate_paging (insertions, paging)
6
- if paging && paging[:offset]
7
- return paging[:offset] < insertions.length
15
+ if paging && paging[:offset] && paging[:offset] >= insertions.length
16
+ raise InvalidPagingError.new("Invalid page offset (insertion size #{insertions.length}, offset #{paging[:offset]})", [])
8
17
  end
9
- return true
10
18
  end
11
19
 
12
20
  def apply_paging (insertions, insertion_page_type, paging = nil)
13
- # This is invalid input, stop it before it goes to the server.
14
- if !validate_paging(insertions, paging)
15
- return []
21
+ begin
22
+ validate_paging(insertions, paging)
23
+ rescue InvalidPagingError => err
24
+ # This is invalid input, stop it before it goes to the server.
25
+ return err.default_insertions_page
16
26
  end
17
27
 
18
28
  if !paging
@@ -54,4 +64,4 @@ module Promoted
54
64
  end
55
65
  end
56
66
  end
57
- end
67
+ end
@@ -99,10 +99,13 @@ module Promoted
99
99
  params = {
100
100
  user_info: user_info,
101
101
  timing: timing,
102
- cohort_membership: @experiment,
103
102
  client_info: @client_info
104
103
  }
105
104
 
105
+ if @experiment
106
+ params[:cohort_membership] = [@experiment]
107
+ end
108
+
106
109
  # Log request allows for multiple requests but here we only send one.
107
110
  if include_request
108
111
  request[:request_id] = request[:request_id] || @id_generator.newID
@@ -1,7 +1,7 @@
1
1
  module Promoted
2
2
  module Ruby
3
3
  module Client
4
- VERSION = "0.1.15"
4
+ VERSION = "0.1.16"
5
5
  end
6
6
  end
7
7
  end
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.15
4
+ version: 0.1.16
5
5
  platform: ruby
6
6
  authors:
7
7
  - scottmcmaster
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-07-24 00:00:00.000000000 Z
11
+ date: 2021-07-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: faraday
@@ -167,7 +167,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
167
167
  - !ruby/object:Gem::Version
168
168
  version: '0'
169
169
  requirements: []
170
- rubygems_version: 3.0.3
170
+ rubygems_version: 3.2.24
171
171
  signing_key:
172
172
  specification_version: 4
173
173
  summary: A Ruby Client to contact Promoted APIs.