Exception: SplitIoClient::SplitAdapter

Inherits:
NoMethodError
  • Object
show all
Defined in:
lib/engine/parser/split_adapter.rb

Overview

acts as an api adapater to connect to split endpoints uses a configuration object that can be modified when creating the client instance also, uses safe threads to execute fetches and post give the time execution values from the config

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(api_key, config, splits_repository, segments_repository, sdk_blocker) ⇒ SplitIoClient

Creates a new split api adapter instance that consumes split api endpoints

Parameters:

  • api_key (String)

    the API key for your split account



42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
# File 'lib/engine/parser/split_adapter.rb', line 42

def initialize(api_key, config, splits_repository, segments_repository, sdk_blocker)

  @api_key = api_key
  @config = config
  @impressions = Impressions.new(100)
  @metrics = Metrics.new(100)

  @splits_repository = splits_repository
  @segments_repository = segments_repository

  @sdk_blocker = sdk_blocker

  @api_client = Faraday.new do |builder|
    builder.use FaradayMiddleware::Gzip
    builder.adapter :net_http_persistent
  end

  @splits_consumer = create_splits_api_consumer
  @segments_consumer = create_segments_api_consumer
  @metrics_producer = create_metrics_api_producer
  @impressions_producer = create_impressions_api_producer

end

Instance Attribute Details

#impressionsObject (readonly)

handler for impressions



18
19
20
# File 'lib/engine/parser/split_adapter.rb', line 18

def impressions
  @impressions
end

#impressions_producerObject (readonly)

Returns the value of attribute impressions_producer.



32
33
34
# File 'lib/engine/parser/split_adapter.rb', line 32

def impressions_producer
  @impressions_producer
end

#metricsObject (readonly)

handler for metrics



22
23
24
# File 'lib/engine/parser/split_adapter.rb', line 22

def metrics
  @metrics
end

#parsed_segmentsObject (readonly)



30
31
32
# File 'lib/engine/parser/split_adapter.rb', line 30

def parsed_segments
  @parsed_segments
end

#parsed_splitsObject (readonly)



26
27
28
# File 'lib/engine/parser/split_adapter.rb', line 26

def parsed_splits
  @parsed_splits
end

#segments_repositoryObject (readonly)

Returns the value of attribute segments_repository.



34
35
36
# File 'lib/engine/parser/split_adapter.rb', line 34

def segments_repository
  @segments_repository
end

#splits_repositoryObject (readonly)

Returns the value of attribute splits_repository.



34
35
36
# File 'lib/engine/parser/split_adapter.rb', line 34

def splits_repository
  @splits_repository
end

Instance Method Details

#create_impressions_api_producerObject



135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
# File 'lib/engine/parser/split_adapter.rb', line 135

def create_impressions_api_producer
  Thread.new do
    loop do
      begin
        #post captured impressions
        post_impressions

        random_interval = randomize_interval @config.impressions_refresh_rate
        sleep(random_interval)
      rescue StandardError => error
        @config.log_found_exception(__method__.to_s, error)
      end
    end
  end
end

#create_metrics_api_producerObject

creates two safe threads that will be executing api calls for posting impressions and metrics given the execution time provided within the configuration



119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
# File 'lib/engine/parser/split_adapter.rb', line 119

def create_metrics_api_producer
  Thread.new do
    loop do
      begin
        #post captured metrics
        post_metrics

        random_interval = randomize_interval @config.metrics_refresh_rate
        sleep(random_interval)
      rescue StandardError => error
        @config.log_found_exception(__method__.to_s, error)
      end
    end
  end
end

#create_segments_api_consumerObject



76
77
78
# File 'lib/engine/parser/split_adapter.rb', line 76

def create_segments_api_consumer
  SplitIoClient::Cache::Stores::SegmentStore.new(@segments_repository, @config, @api_key, @metrics, @sdk_blocker).call
end

#create_splits_api_consumervoid

This method returns an undefined value.

creates a safe thread that will be executing api calls for fetching splits and segments give the execution time provided within the configuration



72
73
74
# File 'lib/engine/parser/split_adapter.rb', line 72

def create_splits_api_consumer
  SplitIoClient::Cache::Stores::SplitStore.new(@splits_repository, @config, @api_key, @metrics, @sdk_blocker).call
end

#post_api(path, param) ⇒ object

helper method to execute a post request to the provided endpoint

Parameters:

  • path (string)

    api endpoint path

  • params (object)

    hash of params that will be added to the request

Returns:

  • (object)

    response to the request



87
88
89
90
91
92
93
94
95
96
97
98
99
# File 'lib/engine/parser/split_adapter.rb', line 87

def post_api(path, param)
  @api_client.post (@config.events_uri + path) do |req|
    req.headers['Authorization'] = 'Bearer ' + @api_key
    req.headers['Content-Type'] = 'application/json'
    req.headers['SplitSDKVersion'] = SplitIoClient::SplitFactory.sdk_version
    req.headers['SplitSDKMachineName'] = @config.machine_name
    req.headers['SplitSDKMachineIP'] = @config.machine_ip
    req.body = param.to_json
    req.options.timeout = @config.read_timeout
    req.options.open_timeout = @config.connection_timeout
    @config.logger.debug("POST #{@config.events_uri + path} #{req.body}") if @config.debug_enabled
  end
end

#post_impressionsvoid

This method returns an undefined value.

creates the appropriate json data for the cached impressions values and then sends them to the appropriate api endpoint with a valid body format



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
# File 'lib/engine/parser/split_adapter.rb', line 156

def post_impressions
  if @impressions.queue.empty?
    @config.logger.debug('No impressions to report.') if @config.debug_enabled
  else
    popped_impressions = @impressions.clear
    test_impression_array = []
    popped_impressions.each do |i|
      filtered = []
      keys_seen = []

      impressions = i[:impressions]
      impressions.each do |imp|
        if keys_seen.include?(imp.key)
          next
        end
        keys_seen << imp.key
        filtered << imp
      end

      if filtered.empty?
        @config.logger.debug('No impressions to report post filtering.') if @config.debug_enabled
      else
        test_impression = {}
        key_impressions = []

        filtered.each do |f|
          key_impressions << {keyName: f.key, treatment: f.treatment, time: f.time.to_i}
        end

        test_impression = {testName: i[:feature], keyImpressions: key_impressions}
        test_impression_array << test_impression
      end
    end

    res = post_api('/testImpressions/bulk', test_impression_array)
    if res.status / 100 != 2
      @config.logger.error("Unexpected status code while posting impressions: #{res.status}")
    else
      @config.logger.debug("Impressions reported: #{test_impression_array}") if @config.debug_enabled
    end
  end
end

#post_metricsvoid

This method returns an undefined value.

creates the appropriate json data for the cached metrics values include latencies, counts and gauges and then sends them to the appropriate api endpoint with a valida body format



205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
# File 'lib/engine/parser/split_adapter.rb', line 205

def post_metrics
  if @metrics.latencies.empty?
    @config.logger.debug('No latencies to report.') if @config.debug_enabled
  else
    @metrics.latencies.each do |l|
      metrics_time = {}
      metrics_time = {name: l[:operation], latencies: l[:latencies]}
      res = post_api('/metrics/time', metrics_time)
      if res.status / 100 != 2
        @config.logger.error("Unexpected status code while posting time metrics: #{res.status}")
      else
        @config.logger.debug("Metric time reported: #{metrics_time}") if @config.debug_enabled
      end
    end
  end
  @metrics.latencies.clear

  if @metrics.counts.empty?
    @config.logger.debug('No counts to report.') if @config.debug_enabled
  else
    @metrics.counts.each do |c|
      metrics_count = {}
      metrics_count = {name: c[:name], delta: c[:delta].sum}
      res = post_api('/metrics/counter', metrics_count)
      if res.status / 100 != 2
        @config.logger.error("Unexpected status code while posting count metrics: #{res.status}")
      else
        @config.logger.debug("Metric counts reported: #{metrics_count}") if @config.debug_enabled
      end
    end
  end
  @metrics.counts.clear

  if @metrics.gauges.empty?
    @config.logger.debug('No gauges to report.') if @config.debug_enabled
  else
    @metrics.gauges.each do |g|
      metrics_gauge = {}
      metrics_gauge = {name: g[:name], value: g[:gauge].value}
      res = post_api('/metrics/gauge', metrics_gauge)
      if res.status / 100 != 2
        @config.logger.error("Unexpected status code while posting gauge metrics: #{res.status}")
      else
        @config.logger.debug("Metric gauge reported: #{metrics_gauge}") if @config.debug_enabled
      end
    end
  end
  @metrics.gauges.clear
end