Module: EppoClient

Defined in:
lib/rules.rb,
lib/shard.rb,
lib/client.rb,
lib/config.rb,
lib/poller.rb,
lib/constants.rb,
lib/lru_cache.rb,
lib/sdk_logger.rb,
lib/validation.rb,
lib/eppo_client.rb,
lib/http_client.rb,
lib/custom_errors.rb,
lib/assignment_logger.rb,
lib/configuration_store.rb,
lib/configuration_requestor.rb

Overview

This module scopes all the client SDK’s classes and functions

Defined Under Namespace

Modules: OperatorType Classes: AllocationDto, AssignmentLogger, AssignmentLoggerError, Client, Condition, Config, ConfigurationStore, ExperimentConfigurationDto, ExperimentConfigurationRequestor, HttpClient, HttpRequestError, InvalidValueError, LRUCache, Poller, Rule, SdkParams, ShardRange, UnauthorizedError, VariationDto

Constant Summary collapse

MAX_CACHE_ENTRIES =

configuration cache constants

1000
SECOND_MILLIS =

poller constants

1000
MINUTE_MILLIS =
60 * SECOND_MILLIS
POLL_JITTER_MILLIS =
30 * SECOND_MILLIS
POLL_INTERVAL_MILLIS =
5 * MINUTE_MILLIS
RAC_ENDPOINT =

the configs endpoint

'randomized_assignment/v2/config'

Class Method Summary collapse

Class Method Details

.evaluate_condition(subject_attributes, condition) ⇒ Object

rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength



51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
# File 'lib/rules.rb', line 51

def evaluate_condition(subject_attributes, condition)
  subject_value = subject_attributes[condition.attribute]
  return false if subject_value.nil?

  case condition.operator
  when OperatorType::MATCHES
    !!(Regexp.new(condition.value) =~ subject_value.to_s)
  when OperatorType::ONE_OF
    condition.value.map(&:downcase).include?(subject_value.to_s.downcase)
  when OperatorType::NOT_ONE_OF
    !condition.value.map(&:downcase).include?(subject_value.to_s.downcase)
  else
    subject_value.is_a?(Numeric) && evaluate_numeric_condition(subject_value, condition)
  end
end

.evaluate_numeric_condition(subject_value, condition) ⇒ Object

rubocop:disable Metrics/MethodLength



69
70
71
72
73
74
75
76
77
78
79
80
81
82
# File 'lib/rules.rb', line 69

def evaluate_numeric_condition(subject_value, condition)
  case condition.operator
  when OperatorType::GT
    subject_value > condition.value
  when OperatorType::GTE
    subject_value >= condition.value
  when OperatorType::LT
    subject_value < condition.value
  when OperatorType::LTE
    subject_value <= condition.value
  else
    false
  end
end

.find_matching_rule(subject_attributes, rules) ⇒ Object



36
37
38
39
40
41
# File 'lib/rules.rb', line 36

def find_matching_rule(subject_attributes, rules)
  rules.each do |rule|
    return rule if matches_rule(subject_attributes, rule)
  end
  nil
end

.get_shard(input, subject_shards) ⇒ Object



21
22
23
24
25
26
27
# File 'lib/shard.rb', line 21

def get_shard(input, subject_shards)
  hash_output = Digest::MD5.hexdigest(input)
  # get the first 4 bytes of the md5 hex string and parse it using base 16
  # (8 hex characters represent 4 bytes, e.g. 0xffffffff represents the max 4-byte integer)
  int_from_hash = hash_output[0...8].to_i(16)
  int_from_hash % subject_shards
end

.init(config) ⇒ Object

rubocop:enable Metrics/MethodLength



32
33
34
35
36
37
38
39
40
41
42
43
# File 'lib/eppo_client.rb', line 32

def init(config)
  config.validate
  sdk_params = EppoClient::SdkParams.new(config.api_key, 'ruby', @sdk_version)
  http_client = EppoClient::HttpClient.new(config.base_url, sdk_params.formatted)
  config_store = EppoClient::ConfigurationStore.new(EppoClient::MAX_CACHE_ENTRIES)
  config_store.lock.with_write_lock do
    EppoClient.initialize_client(
      EppoClient::ExperimentConfigurationRequestor.new(http_client, config_store),
      config.assignment_logger
    )
  end
end

.initialize_client(config_requestor, assignment_logger) ⇒ Object

rubocop:disable Metrics/MethodLength



17
18
19
20
21
22
23
24
25
26
27
28
29
# File 'lib/eppo_client.rb', line 17

def initialize_client(config_requestor, assignment_logger)
  client = EppoClient::Client.instance
  !client.poller.nil? && client.shutdown
  client.config_requestor = config_requestor
  client.assignment_logger = assignment_logger
  client.poller = EppoClient::Poller.new(
    EppoClient::POLL_INTERVAL_MILLIS,
    EppoClient::POLL_JITTER_MILLIS,
    proc { client.config_requestor.fetch_and_store_configurations }
  )
  client.poller.start
  client
end

.logger(type) ⇒ Object



10
11
12
13
14
15
16
17
18
19
# File 'lib/sdk_logger.rb', line 10

def self.logger(type)
  case type
  when 'out'
    @stdout_logger
  when 'err'
    @stderr_logger
  else
    @stderr_logger.error("[Eppo SDK] Invalid logger type: #{type}")
  end
end

.matches_rule(subject_attributes, rule) ⇒ Object



43
44
45
46
47
48
# File 'lib/rules.rb', line 43

def matches_rule(subject_attributes, rule)
  rule.conditions.each do |condition|
    return false unless evaluate_condition(subject_attributes, condition)
  end
  true
end

.validate_not_blank(field_name, field_value) ⇒ Object



7
8
9
# File 'lib/validation.rb', line 7

def validate_not_blank(field_name, field_value)
  (field_value.nil? || field_value == '') && raise(EppoClient::InvalidValueError, "#{field_name} cannot be blank")
end