splitclient-rb 5.1.3.pre.rc1 → 5.1.3.pre.rc2

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: 7470b6e84f8bf0cef00815acc17c0fa9d1f8ab81e6746676b19e9119ce12ba1f
4
- data.tar.gz: 7d95234b01d68aa0da0bdf8a3dd07849836ca3a9194e9a56094bb054e597c0d4
3
+ metadata.gz: 88734d846f562241cc964056ada17c518d5517d31c4096252b461d600955ca2b
4
+ data.tar.gz: aa3a438418ba809ca40fdfd0d5149cefd829dd227942cc1d730387dfa89077eb
5
5
  SHA512:
6
- metadata.gz: bc1135d77d83d1c037716ce4aaa2f9a9f40bcb386cc0efa1665bcd82e2fa2294907d1bc1f42e8fa72541179761d22965c0daee1b51a354677a5ca4bc5d20dc26
7
- data.tar.gz: 9bc52d47fb482081015c4849e15105142de7033880f5d3de1cbef5a8766636389a055e35b4dfa5986a6e63136cc760ba945c702d80a31ae16cde8ad655a71906
6
+ metadata.gz: 6379d29aa2f9bc96b43adfcd14578a9e5f397ff62195085d4325bf9df6f3caa6e5c81c718910d9777437b6acc44128728866e9fc60139e863f04eb4f40d34834
7
+ data.tar.gz: f8f8003bdaf8a63637ddee8b3735e26f8929694fd6ec8d4112382f7945e6fa80a5f057bc56a979909a1bc8a2fafb4fc07b966e9bdb2437a59079f0c225e1b658
data/.rubocop.yml CHANGED
@@ -1,3 +1,6 @@
1
+ Documentation:
2
+ Enabled: false
3
+
1
4
  Metrics/MethodLength:
2
5
  Max: 15
3
6
 
data/CHANGES.txt CHANGED
@@ -1,5 +1,5 @@
1
1
  5.1.3
2
- - Add cache wrapper to treatments and segments.
2
+ - Add cache wrapper to splits and segments.
3
3
 
4
4
  5.1.2 (October 26th, 2018)
5
5
  - Add input validation for client API methods
data/NEWS CHANGED
@@ -1,6 +1,6 @@
1
1
  5.1.3
2
2
 
3
- Add cache wrapper to treatments and segments.
3
+ Add cache wrapper to splits and segments.
4
4
 
5
5
  5.1.2
6
6
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'json'
2
4
 
3
5
  module SplitIoClient
@@ -85,8 +87,8 @@ module SplitIoClient
85
87
  end
86
88
 
87
89
  # Set
88
- alias_method :initialize_set, :initialize_map
89
- alias_method :find_sets_by_prefix, :find_strings_by_prefix
90
+ alias initialize_set initialize_map
91
+ alias find_sets_by_prefix find_strings_by_prefix
90
92
 
91
93
  def add_to_set(key, val)
92
94
  @redis.sadd(key, val)
@@ -126,7 +128,7 @@ module SplitIoClient
126
128
  def get_from_queue(key, count)
127
129
  items = @redis.lrange(key, 0, count - 1)
128
130
  fetched_count = items.size
129
- items_to_remove = (fetched_count == count) ? count : fetched_count
131
+ items_to_remove = fetched_count == count ? count : fetched_count
130
132
 
131
133
  @redis.ltrim(key, items_to_remove, -1)
132
134
 
@@ -148,9 +150,9 @@ module SplitIoClient
148
150
  @redis.incrby(key, inc)
149
151
  end
150
152
 
151
- def pipelined(&block)
153
+ def pipelined
152
154
  @redis.pipelined do
153
- block.call
155
+ yield
154
156
  end
155
157
  end
156
158
 
@@ -159,6 +161,10 @@ module SplitIoClient
159
161
 
160
162
  keys.map { |key| @redis.del(key) }
161
163
  end
164
+
165
+ def expire(key, seconds)
166
+ @redis.expire(key, seconds)
167
+ end
162
168
  end
163
169
  end
164
170
  end
@@ -1,42 +1,44 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module SplitIoClient
2
4
  module Cache
3
5
  module Repositories
4
6
  module Impressions
5
- class MemoryRepository
6
-
7
+ class MemoryRepository < ImpressionsRepository
7
8
  def initialize(adapter)
8
9
  @adapter = adapter
9
10
  end
10
11
 
11
12
  # Store impression data in the selected adapter
12
- def add(split_name, data)
13
- @adapter.add_to_queue(feature: split_name, impressions: data)
13
+ def add(matching_key, bucketing_key, split_name, treatment, time)
14
+ @adapter.add_to_queue(
15
+ m: metadata,
16
+ i: impression_data(
17
+ matching_key,
18
+ bucketing_key,
19
+ split_name,
20
+ treatment,
21
+ time
22
+ )
23
+ )
14
24
  rescue ThreadError # queue is full
15
25
  if random_sampler.rand(1..1000) <= 2 # log only 0.2 % of the time
16
- SplitIoClient.configuration.logger.warn("Dropping impressions. Current size is #{SplitIoClient.configuration.impressions_queue_size}. " \
17
- "Consider increasing impressions_queue_size")
26
+ SplitIoClient.configuration.logger.warn("Dropping impressions. Current size is \
27
+ #{SplitIoClient.configuration.impressions_queue_size}. " \
28
+ 'Consider increasing impressions_queue_size')
18
29
  end
19
30
  end
20
31
 
21
32
  def add_bulk(key, bucketing_key, treatments, time)
22
33
  treatments.each do |split_name, treatment|
23
- add(
24
- split_name,
25
- 'keyName' => key,
26
- 'bucketingKey' => bucketing_key,
27
- 'treatment' => treatment[:treatment],
28
- 'label' => SplitIoClient.configuration.labels_enabled ? treatment[:label] : nil,
29
- 'changeNumber' => treatment[:change_number],
30
- 'time' => time
31
- )
34
+ add(key, bucketing_key, split_name, treatment, time)
32
35
  end
33
36
  end
34
37
 
35
- def get_batch
36
- return [] if SplitIoClient.configuration.impressions_bulk_size == 0
37
- @adapter.get_batch(SplitIoClient.configuration.impressions_bulk_size).map do |impression|
38
- impression.update(ip: SplitIoClient.configuration.machine_ip)
39
- end
38
+ def batch
39
+ return [] if SplitIoClient.configuration.impressions_bulk_size.zero?
40
+
41
+ @adapter.get_batch(SplitIoClient.configuration.impressions_bulk_size)
40
42
  end
41
43
 
42
44
  private
@@ -1,75 +1,53 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module SplitIoClient
2
4
  module Cache
3
5
  module Repositories
4
6
  module Impressions
5
- class RedisRepository < Repository
7
+ class RedisRepository < ImpressionsRepository
8
+ EXPIRE_SECONDS = 3600
6
9
 
7
10
  def initialize(adapter)
8
11
  @adapter = adapter
9
12
  end
10
13
 
11
- # Store impression data in Redis
12
- def add(split_name, data)
13
- @adapter.add_to_set(
14
- impressions_metrics_key("impressions.#{split_name}"),
15
- data.to_json
16
- )
14
+ def add(matching_key, bucketing_key, split_name, treatment, time)
15
+ add_bulk(matching_key, bucketing_key, { split_name => treatment }, time)
17
16
  end
18
17
 
19
- def add_bulk(key, bucketing_key, treatments, time)
20
- @adapter.redis.pipelined do
21
- treatments.each do |split_name, treatment|
22
- add(split_name,
23
- 'keyName' => key,
24
- 'bucketingKey' => bucketing_key,
25
- 'treatment' => treatment[:treatment],
26
- 'label' => SplitIoClient.configuration.labels_enabled ? treatment[:label] : nil,
27
- 'changeNumber' => treatment[:change_number],
28
- 'time' => time)
29
- end
18
+ def add_bulk(matching_key, bucketing_key, treatments, time)
19
+ impressions = treatments.map do |split_name, treatment|
20
+ {
21
+ m: metadata,
22
+ i: impression_data(
23
+ matching_key,
24
+ bucketing_key,
25
+ split_name,
26
+ treatment,
27
+ time
28
+ )
29
+ }.to_json
30
30
  end
31
- end
32
-
33
- # Get random impressions from redis in batches of size SplitIoClient.configuration.impressions_bulk_size,
34
- # delete fetched impressions afterwards
35
- def get_batch
36
- impressions = impression_keys.each_with_object([]) do |key, memo|
37
- ip = key.split('/')[-2] # 'prefix/sdk_lang/ip/impressions.name' -> ip
38
- if ip.nil?
39
- SplitIoClient.configuration.logger.warn("Impressions IP parse error for key: #{key}")
40
- next
41
- end
42
- split_name = key.split('.').last
43
- members = @adapter.random_set_elements(key, SplitIoClient.configuration.impressions_bulk_size)
44
- members.each do |impression|
45
- parsed_impression = JSON.parse(impression)
46
31
 
47
- memo << {
48
- feature: split_name.to_sym,
49
- impressions: parsed_impression,
50
- ip: ip
51
- }
52
- end
32
+ impressions_list_size = @adapter.add_to_queue(key, impressions)
53
33
 
54
- @adapter.delete_from_set(key, members)
34
+ # Synchronizer might not be running
35
+ @adapter.expire(key, EXPIRE_SECONDS) if impressions.size == impressions_list_size
36
+ end
55
37
 
38
+ def batch
39
+ @adapter.get_from_queue(key, SplitIoClient.configuration.impressions_bulk_size).map do |e|
40
+ impression = JSON.parse(e, symbolize_names: true)
41
+ impression[:i][:f] = impression[:i][:f].to_sym
42
+ impression
56
43
  end
57
- impressions
58
44
  rescue StandardError => e
59
45
  SplitIoClient.configuration.logger.error("Exception while clearing impressions cache: #{e}")
60
-
61
46
  []
62
47
  end
63
48
 
64
- private
65
-
66
- # Get all sets by prefix
67
- def impression_keys
68
- @adapter.find_sets_by_prefix("#{SplitIoClient.configuration.redis_namespace}/*/impressions.*")
69
- rescue StandardError => e
70
- SplitIoClient.configuration.logger.error("Exception while fetching impression_keys: #{e}")
71
-
72
- []
49
+ def key
50
+ @key ||= namespace_key('.impressions')
73
51
  end
74
52
  end
75
53
  end
@@ -1,18 +1,46 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module SplitIoClient
2
4
  module Cache
3
5
  module Repositories
4
6
  # Repository which forwards impressions interface to the selected adapter
5
7
  class ImpressionsRepository < Repository
6
8
  extend Forwardable
7
- def_delegators :@adapter, :add, :add_bulk, :get_batch, :empty?
9
+ def_delegators :@adapter, :add, :add_bulk, :batch, :empty?
8
10
 
9
11
  def initialize(adapter)
10
12
  @adapter = case adapter.class.to_s
11
- when 'SplitIoClient::Cache::Adapters::MemoryAdapter'
12
- Repositories::Impressions::MemoryRepository.new(adapter)
13
- when 'SplitIoClient::Cache::Adapters::RedisAdapter'
14
- Repositories::Impressions::RedisRepository.new(adapter)
15
- end
13
+ when 'SplitIoClient::Cache::Adapters::MemoryAdapter'
14
+ Repositories::Impressions::MemoryRepository.new(adapter)
15
+ when 'SplitIoClient::Cache::Adapters::RedisAdapter'
16
+ Repositories::Impressions::RedisRepository.new(adapter)
17
+ end
18
+ end
19
+
20
+ protected
21
+
22
+ def impression_data(matching_key, bucketing_key, split_name, treatment, timestamp)
23
+ {
24
+ k: matching_key,
25
+ b: bucketing_key,
26
+ f: split_name,
27
+ t: treatment[:treatment],
28
+ r: applied_rule(treatment[:label]),
29
+ c: treatment[:change_number],
30
+ m: timestamp
31
+ }
32
+ end
33
+
34
+ def metadata
35
+ {
36
+ s: "#{SplitIoClient.configuration.language}-#{SplitIoClient.configuration.version}",
37
+ i: SplitIoClient.configuration.machine_ip,
38
+ n: SplitIoClient.configuration.machine_name
39
+ }
40
+ end
41
+
42
+ def applied_rule(label)
43
+ SplitIoClient.configuration.labels_enabled ? label : nil
16
44
  end
17
45
  end
18
46
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module SplitIoClient
2
4
  module Cache
3
5
  module Senders
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module SplitIoClient
2
4
  module Cache
3
5
  module Senders
@@ -7,29 +9,15 @@ module SplitIoClient
7
9
  end
8
10
 
9
11
  def call(raw_impressions)
10
- impressions = raw_impressions ? raw_impressions : @impressions_repository.get_batch
11
- formatted_impressions = []
12
+ impressions = raw_impressions || @impressions_repository.batch
12
13
  filtered_impressions = filter_impressions(impressions)
13
14
 
14
15
  return [] if impressions.empty? || filtered_impressions.empty?
15
16
 
16
17
  formatted_impressions = unique_features(filtered_impressions).each_with_object([]) do |feature, memo|
17
- ip = nil
18
- current_impressions =
19
- filtered_impressions
20
- .select { |impression| impression[:feature] == feature }
21
- .map do |impression|
22
- ip = impression[:ip]
23
- {
24
- keyName: impression[:impressions]['keyName'] || impression[:impressions]['key_name'],
25
- treatment: impression[:impressions]['treatment'],
26
- time: impression[:impressions]['time'],
27
- bucketingKey: impression[:impressions]['bucketingKey'] || impression[:impressions]['bucketing_key'],
28
- label: impression[:impressions]['label'],
29
- changeNumber: impression[:impressions]['changeNumber'] || impression[:impressions]['change_number'],
30
- }
31
- end
32
-
18
+ feature_impressions = feature_impressions(filtered_impressions, feature)
19
+ ip = feature_impressions.first[:m][:i]
20
+ current_impressions = current_impressions(feature_impressions)
33
21
  memo << {
34
22
  testName: feature.to_sym,
35
23
  keyImpressions: current_impressions,
@@ -42,8 +30,27 @@ module SplitIoClient
42
30
 
43
31
  private
44
32
 
33
+ def feature_impressions(filtered_impressions, feature)
34
+ filtered_impressions.select do |impression|
35
+ impression[:i][:f] == feature
36
+ end
37
+ end
38
+
39
+ def current_impressions(feature_impressions)
40
+ feature_impressions.map do |impression|
41
+ {
42
+ keyName: impression[:i][:k],
43
+ treatment: impression[:i][:t],
44
+ time: impression[:i][:m],
45
+ bucketingKey: impression[:i][:b],
46
+ label: impression[:i][:r],
47
+ changeNumber: impression[:i][:c]
48
+ }
49
+ end
50
+ end
51
+
45
52
  def unique_features(impressions)
46
- impressions.map { |impression| impression[:feature] }.uniq
53
+ impressions.map { |impression| impression[:i][:f] }.uniq
47
54
  end
48
55
 
49
56
  # Filter seen impressions by impression_hash
@@ -61,11 +68,11 @@ module SplitIoClient
61
68
  end
62
69
 
63
70
  def impression_hash(impression)
64
- "#{impression[:feature]}:" \
65
- "#{impression[:impressions]['keyName']}:" \
66
- "#{impression[:impressions]['bucketingKey']}:" \
67
- "#{impression[:impressions]['changeNumber']}:" \
68
- "#{impression[:impressions]['treatment']}"
71
+ "#{impression[:i][:f]}:" \
72
+ "#{impression[:i][:k]}:" \
73
+ "#{impression[:i][:b]}:" \
74
+ "#{impression[:i][:c]}:" \
75
+ "#{impression[:i][:t]}"
69
76
  end
70
77
  end
71
78
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module SplitIoClient
2
4
  module Cache
3
5
  module Senders
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module SplitIoClient
2
4
  module Cache
3
5
  module Senders
@@ -136,13 +136,12 @@ module SplitIoClient
136
136
 
137
137
  return if SplitIoClient.configuration.disable_impressions || !store_impressions
138
138
 
139
- @impressions_repository.add(split_name,
140
- 'keyName' => matching_key,
141
- 'bucketingKey' => bucketing_key,
142
- 'treatment' => treatment[:treatment],
143
- 'label' => SplitIoClient.configuration.labels_enabled ? treatment[:label] : nil,
144
- 'time' => time,
145
- 'changeNumber' => treatment[:change_number]
139
+ @impressions_repository.add(
140
+ matching_key,
141
+ bucketing_key,
142
+ split_name,
143
+ treatment,
144
+ time
146
145
  )
147
146
 
148
147
  route_impression(split_name, matching_key, bucketing_key, time, treatment, attributes)
@@ -1,3 +1,3 @@
1
1
  module SplitIoClient
2
- VERSION = '5.1.3.pre.rc1'
2
+ VERSION = '5.1.3.pre.rc2'
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: splitclient-rb
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.1.3.pre.rc1
4
+ version: 5.1.3.pre.rc2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Split Software
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-11-05 00:00:00.000000000 Z
11
+ date: 2018-12-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: allocation_stats