Class: Promoted::Ruby::Client::PromotedClient
- Inherits:
-
Object
- Object
- Promoted::Ruby::Client::PromotedClient
- Defined in:
- lib/promoted/ruby/client.rb
Overview
Client for working with Promoted’s Metrics and Delivery APIs. See Github for more info.
Defined Under Namespace
Classes: Error
Instance Attribute Summary collapse
-
#async_shadow_traffic ⇒ Object
readonly
Returns the value of attribute async_shadow_traffic.
-
#default_only_log ⇒ Object
readonly
Returns the value of attribute default_only_log.
-
#default_request_headers ⇒ Object
readonly
Returns the value of attribute default_request_headers.
-
#delivery_timeout_millis ⇒ Object
readonly
Returns the value of attribute delivery_timeout_millis.
-
#enabled ⇒ Object
Returns the value of attribute enabled.
-
#http_client ⇒ Object
readonly
Returns the value of attribute http_client.
-
#logger ⇒ Object
readonly
Returns the value of attribute logger.
-
#max_request_insertions ⇒ Object
readonly
Returns the value of attribute max_request_insertions.
-
#metrics_timeout_millis ⇒ Object
readonly
Returns the value of attribute metrics_timeout_millis.
-
#perform_checks ⇒ Object
readonly
Returns the value of attribute perform_checks.
-
#request_logging_on ⇒ Object
Returns the value of attribute request_logging_on.
-
#send_shadow_traffic_for_control ⇒ Object
readonly
Returns the value of attribute send_shadow_traffic_for_control.
-
#shadow_traffic_delivery_percent ⇒ Object
readonly
Returns the value of attribute shadow_traffic_delivery_percent.
-
#should_apply_treatment_func ⇒ Object
readonly
Returns the value of attribute should_apply_treatment_func.
Instance Method Summary collapse
-
#close ⇒ Object
Politely shut down a Promoted client.
-
#deliver(args, headers = {}) ⇒ Object
Make a delivery request.
-
#enabled? ⇒ Boolean
Whether or not the client is currently enabled for execution.
-
#initialize(params = {}) ⇒ PromotedClient
constructor
Create and configure a new Promoted client.
-
#send_log_request(log_request_params, headers = {}) ⇒ Object
Sends a log request to the metrics endpoint.
Constructor Details
#initialize(params = {}) ⇒ PromotedClient
Create and configure a new Promoted client.
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 |
# File 'lib/promoted/ruby/client.rb', line 36 def initialize(params={}) @perform_checks = true if params[:perform_checks] != nil @perform_checks = params[:perform_checks] end @logger = params[:logger] # Example: Logger.new(STDERR, :progname => "promotedai") @request_logging_on = params[:request_logging_on] || false @default_request_headers = params[:default_request_headers] || {} @metrics_api_key = params[:metrics_api_key] || '' @delivery_api_key = params[:delivery_api_key] || '' @default_only_log = params[:default_only_log] || false @should_apply_treatment_func = params[:should_apply_treatment_func] @shadow_traffic_delivery_percent = params[:shadow_traffic_delivery_percent] || 0.0 raise ArgumentError.new("Invalid shadow_traffic_delivery_percent, must be between 0 and 1") if @shadow_traffic_delivery_percent < 0 || @shadow_traffic_delivery_percent > 1.0 @sampler = Sampler.new @pager = Pager.new # HTTP Client creation @delivery_endpoint = params[:delivery_endpoint] || DEFAULT_DELIVERY_ENDPOINT raise ArgumentError.new("delivery_endpoint is required") if @delivery_endpoint.strip.empty? @metrics_endpoint = params[:metrics_endpoint] || DEFAULT_METRICS_ENDPOINT raise ArgumentError.new("metrics_endpoint is required") if @metrics_endpoint.strip.empty? @delivery_timeout_millis = params[:delivery_timeout_millis] || DEFAULT_DELIVERY_TIMEOUT_MILLIS @metrics_timeout_millis = params[:metrics_timeout_millis] || DEFAULT_METRICS_TIMEOUT_MILLIS @http_client = FaradayHTTPClient.new(@logger) @validator = Promoted::Ruby::Client::Validator.new @async_shadow_traffic = true if params[:async_shadow_traffic] != nil @async_shadow_traffic = params[:async_shadow_traffic] || false end @send_shadow_traffic_for_control = true if params[:send_shadow_traffic_for_control] != nil @send_shadow_traffic_for_control = params[:send_shadow_traffic_for_control] || false end @max_request_insertions = params[:max_request_insertions] || DEFAULT_MAX_REQUEST_INSERTIONS @pool = nil if @async_shadow_traffic # Thread pool to process delivery of shadow traffic. Will silently drop excess requests beyond the queue # size, and silently eat errors on the background threads. @pool = Concurrent::ThreadPoolExecutor.new( min_threads: 0, max_threads: 10, max_queue: 100, fallback_policy: :discard ) end @enabled = true if params[:enabled] != nil @enabled = params[:enabled] || false end if params[:warmup] do_warmup end end |
Instance Attribute Details
#async_shadow_traffic ⇒ Object (readonly)
Returns the value of attribute async_shadow_traffic.
22 23 24 |
# File 'lib/promoted/ruby/client.rb', line 22 def async_shadow_traffic @async_shadow_traffic end |
#default_only_log ⇒ Object (readonly)
Returns the value of attribute default_only_log.
22 23 24 |
# File 'lib/promoted/ruby/client.rb', line 22 def default_only_log @default_only_log end |
#default_request_headers ⇒ Object (readonly)
Returns the value of attribute default_request_headers.
22 23 24 |
# File 'lib/promoted/ruby/client.rb', line 22 def default_request_headers @default_request_headers end |
#delivery_timeout_millis ⇒ Object (readonly)
Returns the value of attribute delivery_timeout_millis.
22 23 24 |
# File 'lib/promoted/ruby/client.rb', line 22 def delivery_timeout_millis @delivery_timeout_millis end |
#enabled ⇒ Object
Returns the value of attribute enabled.
26 27 28 |
# File 'lib/promoted/ruby/client.rb', line 26 def enabled @enabled end |
#http_client ⇒ Object (readonly)
Returns the value of attribute http_client.
22 23 24 |
# File 'lib/promoted/ruby/client.rb', line 22 def http_client @http_client end |
#logger ⇒ Object (readonly)
Returns the value of attribute logger.
22 23 24 |
# File 'lib/promoted/ruby/client.rb', line 22 def logger @logger end |
#max_request_insertions ⇒ Object (readonly)
Returns the value of attribute max_request_insertions.
22 23 24 |
# File 'lib/promoted/ruby/client.rb', line 22 def max_request_insertions @max_request_insertions end |
#metrics_timeout_millis ⇒ Object (readonly)
Returns the value of attribute metrics_timeout_millis.
22 23 24 |
# File 'lib/promoted/ruby/client.rb', line 22 def metrics_timeout_millis @metrics_timeout_millis end |
#perform_checks ⇒ Object (readonly)
Returns the value of attribute perform_checks.
22 23 24 |
# File 'lib/promoted/ruby/client.rb', line 22 def perform_checks @perform_checks end |
#request_logging_on ⇒ Object
Returns the value of attribute request_logging_on.
26 27 28 |
# File 'lib/promoted/ruby/client.rb', line 26 def request_logging_on @request_logging_on end |
#send_shadow_traffic_for_control ⇒ Object (readonly)
Returns the value of attribute send_shadow_traffic_for_control.
22 23 24 |
# File 'lib/promoted/ruby/client.rb', line 22 def send_shadow_traffic_for_control @send_shadow_traffic_for_control end |
#shadow_traffic_delivery_percent ⇒ Object (readonly)
Returns the value of attribute shadow_traffic_delivery_percent.
22 23 24 |
# File 'lib/promoted/ruby/client.rb', line 22 def shadow_traffic_delivery_percent @shadow_traffic_delivery_percent end |
#should_apply_treatment_func ⇒ Object (readonly)
Returns the value of attribute should_apply_treatment_func.
22 23 24 |
# File 'lib/promoted/ruby/client.rb', line 22 def should_apply_treatment_func @should_apply_treatment_func end |
Instance Method Details
#close ⇒ Object
Politely shut down a Promoted client.
107 108 109 110 111 112 |
# File 'lib/promoted/ruby/client.rb', line 107 def close if @pool @pool.shutdown @pool.wait_for_termination end end |
#deliver(args, headers = {}) ⇒ Object
Make a delivery request. If @perform_checks is set, input validation will occur and possibly raise errors.
116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 |
# File 'lib/promoted/ruby/client.rb', line 116 def deliver args, headers={} args = Promoted::Ruby::Client::Util.translate_hash(args) retrieval_insertion_offset = args[:retrieval_insertion_offset] || 0 # Respect the enabled state if !@enabled return { insertion: @pager.apply_paging(args[:request][:insertion], retrieval_insertion_offset, args[:request][:paging]) # No log request returned when disabled } end delivery_request_builder = RequestBuilder.new delivery_request_builder.set_request_params(args) only_log = delivery_request_builder.only_log != nil ? delivery_request_builder.only_log : @default_only_log # Gets modified depending on the call. should_send_shadow_traffic = @shadow_traffic_delivery_percent > 0 # perform_checks raises errors. if @perform_checks perform_common_checks!(args) end delivery_request_builder. response_insertions = [] cohort_membership_to_log = nil insertions_from_delivery = false deliver_err = false # Trim any request insertions over the maximum allowed. if delivery_request_builder.insertion.length > @max_request_insertions then @logger.warn("Exceeded max request insertions, trimming") if @logger delivery_request_builder.insertion = delivery_request_builder.insertion[0, @max_request_insertions] end begin @pager.validate_paging(delivery_request_builder.insertion, retrieval_insertion_offset, delivery_request_builder.request[:paging]) rescue InvalidPagingError => err # Invalid input, log and do SDK-side delivery. @logger.warn(err) if @logger return { insertion: err.default_insertions_page # No log request returned when no response insertions due to invalid paging } end if !only_log cohort_membership_to_log = delivery_request_builder.new_cohort_membership_to_log if should_apply_treatment(cohort_membership_to_log) # Call Delivery API to get insertions to use delivery_request_params = delivery_request_builder.delivery_request_params # Don't send shadow traffic if we've already tried normal traffic. should_send_shadow_traffic = false begin response = send_request(delivery_request_params, @delivery_endpoint, @delivery_timeout_millis, @delivery_api_key, headers) @validator.validate_response!(response) raise ValidationError.new("Response shoul be a Hash") if !response.is_a?(Hash) response_insertions = response && response[:insertion] || [] insertions_from_delivery = (response != nil && !deliver_err); rescue StandardError => err # Currently we don't propagate errors to the SDK caller, but rather default to returning # the request insertions. deliver_err = true @logger.error("Error calling delivery: " + err.) if @logger end else should_send_shadow_traffic &&= @send_shadow_traffic_for_control end end should_send_shadow_traffic &&= should_send_as_shadow_traffic? if should_send_shadow_traffic then # Call Delivery API to send shadow traffic. This will create the request params with traffic type set. deliver_shadow_traffic args, headers end if !insertions_from_delivery then response_insertions = build_sdk_response_insertions(delivery_request_builder, retrieval_insertion_offset) end log_req = nil exec_server = (insertions_from_delivery ? Promoted::Ruby::Client::EXECUTION_SERVER['API'] : Promoted::Ruby::Client::EXECUTION_SERVER['SDK']) # We only return a log request if there's a request or cohort to log. if !insertions_from_delivery || cohort_membership_to_log log_request_builder = LogRequestBuilder.new # TODO - make this more efficient. log_request_builder.request = delivery_request_builder.delivery_request_params log_request_builder.response_insertions = response_insertions log_request_builder.experiment = cohort_membership_to_log # On a successful delivery request, we don't log the insertions # or the request since they are logged on the server-side. log_req = log_request_builder.log_request( include_delivery_log: !insertions_from_delivery, exec_server: exec_server) end client_response = { insertion: response_insertions, log_request: log_req, execution_server: exec_server, client_request_id: delivery_request_builder.client_request_id } return client_response end |
#enabled? ⇒ Boolean
Whether or not the client is currently enabled for execution.
30 31 32 |
# File 'lib/promoted/ruby/client.rb', line 30 def enabled? @enabled end |
#send_log_request(log_request_params, headers = {}) ⇒ Object
Sends a log request to the metrics endpoint.
229 230 231 232 233 234 235 236 |
# File 'lib/promoted/ruby/client.rb', line 229 def send_log_request log_request_params, headers={} begin send_request(log_request_params, @metrics_endpoint, @metrics_timeout_millis, @metrics_api_key, headers) rescue StandardError => err # Currently we don't propagate errors to the SDK caller. @logger.error("Error from metrics: " + err.) if @logger end end |