splitclient-rb 7.3.4.pre.rc2-java → 7.3.5.pre.rc1-java
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/workflows/update-license-year.yml +45 -0
- data/.rubocop.yml +2 -1
- data/CHANGES.txt +5 -1
- data/LICENSE +1 -1
- data/lib/splitclient-rb/cache/filter/filter_adapter.rb +32 -0
- data/lib/splitclient-rb/cache/observers/noop_impression_observer.rb +10 -0
- data/lib/splitclient-rb/cache/senders/impressions_adapter/memory_sender.rb +71 -0
- data/lib/splitclient-rb/cache/senders/impressions_adapter/redis_sender.rb +77 -0
- data/lib/splitclient-rb/cache/senders/impressions_count_sender.rb +6 -30
- data/lib/splitclient-rb/cache/senders/impressions_sender_adapter.rb +21 -0
- data/lib/splitclient-rb/engine/api/telemetry_api.rb +8 -0
- data/lib/splitclient-rb/engine/common/impressions_manager.rb +55 -40
- data/lib/splitclient-rb/engine/common/noop_impressions_counter.rb +27 -0
- data/lib/splitclient-rb/engine/impressions/noop_unique_keys_tracker.rb +17 -0
- data/lib/splitclient-rb/engine/impressions/unique_keys_tracker.rb +97 -0
- data/lib/splitclient-rb/engine/matchers/combining_matcher.rb +2 -3
- data/lib/splitclient-rb/engine/sync_manager.rb +13 -0
- data/lib/splitclient-rb/engine/synchronizer.rb +16 -8
- data/lib/splitclient-rb/split_config.rb +36 -0
- data/lib/splitclient-rb/split_factory.rb +58 -10
- data/lib/splitclient-rb/telemetry/memory/memory_synchronizer.rb +3 -1
- data/lib/splitclient-rb/utilitites.rb +12 -0
- data/lib/splitclient-rb/version.rb +1 -1
- data/lib/splitclient-rb.rb +8 -0
- data/splitclient-rb.gemspec +1 -0
- metadata +25 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 52ee386fb2542467575c4f58ddfd25b3d33ff33e
|
4
|
+
data.tar.gz: 6a6d7cd53ca3d0c7ad30c8fa8d3621c43e9a63d2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fb3e3c3dac2de8df3994d40bb10ba3dddf1e1ca8ae382a144980ddb8ba61ff76fb4dad4f40ce4755ed0f81e63650f84ca238c9b4c1353db86dfa39891131be88
|
7
|
+
data.tar.gz: f68eb21afac8f031a56eecb358d1e79520f38036b44f20f0596e07163b1cf1c4b50263f419b9388d556d2e919f206bffa17bd4f16e7f25276ba6d592487b3268
|
@@ -0,0 +1,45 @@
|
|
1
|
+
name: Update License Year
|
2
|
+
|
3
|
+
on:
|
4
|
+
schedule:
|
5
|
+
- cron: "0 3 1 1 *" # 03:00 AM on January 1
|
6
|
+
|
7
|
+
permissions:
|
8
|
+
contents: write
|
9
|
+
pull-requests: write
|
10
|
+
|
11
|
+
jobs:
|
12
|
+
test:
|
13
|
+
runs-on: ubuntu-latest
|
14
|
+
steps:
|
15
|
+
- name: Checkout
|
16
|
+
uses: actions/checkout@v2
|
17
|
+
with:
|
18
|
+
fetch-depth: 0
|
19
|
+
|
20
|
+
- name: Set Current year
|
21
|
+
run: "echo CURRENT=$(date +%Y) >> $GITHUB_ENV"
|
22
|
+
|
23
|
+
- name: Set Previous Year
|
24
|
+
run: "echo PREVIOUS=$(($CURRENT-1)) >> $GITHUB_ENV"
|
25
|
+
|
26
|
+
- name: Update LICENSE
|
27
|
+
uses: jacobtomlinson/gha-find-replace@v2
|
28
|
+
with:
|
29
|
+
find: ${{ env.PREVIOUS }}
|
30
|
+
replace: ${{ env.CURRENT }}
|
31
|
+
include: "LICENSE"
|
32
|
+
regex: false
|
33
|
+
|
34
|
+
- name: Commit files
|
35
|
+
run: |
|
36
|
+
git config user.name 'github-actions[bot]'
|
37
|
+
git config user.email 'github-actions[bot]@users.noreply.github.com'
|
38
|
+
git commit -m "Updated License Year" -a
|
39
|
+
|
40
|
+
- name: Create Pull Request
|
41
|
+
uses: peter-evans/create-pull-request@v3
|
42
|
+
with:
|
43
|
+
token: ${{ secrets.GITHUB_TOKEN }}
|
44
|
+
title: Update License Year
|
45
|
+
branch: update-license
|
data/.rubocop.yml
CHANGED
@@ -26,7 +26,7 @@ Metrics/ParameterLists:
|
|
26
26
|
- lib/splitclient-rb/engine/sync_manager.rb
|
27
27
|
|
28
28
|
Metrics/LineLength:
|
29
|
-
Max:
|
29
|
+
Max: 135
|
30
30
|
Exclude:
|
31
31
|
- spec/sse/**/*
|
32
32
|
- spec/integrations/**/*
|
@@ -35,6 +35,7 @@ Metrics/LineLength:
|
|
35
35
|
- spec/telemetry/synchronizer_spec.rb
|
36
36
|
- spec/splitclient/split_config_spec.rb
|
37
37
|
- spec/engine/push_manager_spec.rb
|
38
|
+
- spec/cache/senders/impressions_sender_adapter_spec.rb
|
38
39
|
|
39
40
|
Style/BracesAroundHashParameters:
|
40
41
|
Exclude:
|
data/CHANGES.txt
CHANGED
@@ -1,6 +1,10 @@
|
|
1
1
|
CHANGES
|
2
2
|
|
3
|
-
7.3.
|
3
|
+
7.3.4 (Feb 21, 2022)
|
4
|
+
- Updated streaming events architecture with a new queue logic.
|
5
|
+
- Fixed redis integration Pipelining command deprecation warning.
|
6
|
+
|
7
|
+
7.3.3 (Jan 28, 2022)
|
4
8
|
- Fixed edge cases where the sdk lost streaming connection.
|
5
9
|
- Updated default auth service url to https://auth.split.io/api/v2/auth
|
6
10
|
- Updated dependencies:
|
data/LICENSE
CHANGED
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module SplitIoClient
|
4
|
+
module Cache
|
5
|
+
module Filter
|
6
|
+
class FilterAdapter
|
7
|
+
def initialize(config, filter)
|
8
|
+
@config = config
|
9
|
+
@filter = filter
|
10
|
+
end
|
11
|
+
|
12
|
+
def add(feature_name, key)
|
13
|
+
@filter.insert("#{feature_name}#{key}")
|
14
|
+
rescue StandardError => e
|
15
|
+
@config.log_found_exception(__method__.to_s, e)
|
16
|
+
end
|
17
|
+
|
18
|
+
def contains?(feature_name, key)
|
19
|
+
@filter.include?("#{feature_name}#{key}")
|
20
|
+
rescue StandardError => e
|
21
|
+
@config.log_found_exception(__method__.to_s, e)
|
22
|
+
end
|
23
|
+
|
24
|
+
def clear
|
25
|
+
@filter.clear
|
26
|
+
rescue StandardError => e
|
27
|
+
@config.log_found_exception(__method__.to_s, e)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module SplitIoClient
|
4
|
+
module Cache
|
5
|
+
module Senders
|
6
|
+
class MemoryImpressionsSender < ImpressionsSenderAdapter
|
7
|
+
def initialize(config, telemetry_api, impressions_api)
|
8
|
+
@config = config
|
9
|
+
@telemetry_api = telemetry_api
|
10
|
+
@impressions_api = impressions_api
|
11
|
+
end
|
12
|
+
|
13
|
+
def record_uniques_key(uniques)
|
14
|
+
uniques_keys = uniques_formatter(uniques)
|
15
|
+
|
16
|
+
@telemetry_api.record_unique_keys(uniques_keys) unless uniques_keys.nil?
|
17
|
+
rescue StandardError => e
|
18
|
+
@config.log_found_exception(__method__.to_s, e)
|
19
|
+
end
|
20
|
+
|
21
|
+
def record_impressions_count(impressions_count)
|
22
|
+
counts = impressions_count_formatter(impressions_count)
|
23
|
+
|
24
|
+
@impressions_api.post_count(counts) unless counts.nil?
|
25
|
+
rescue StandardError => e
|
26
|
+
@config.log_found_exception(__method__.to_s, e)
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def uniques_formatter(uniques)
|
32
|
+
return if uniques.nil? || uniques.empty?
|
33
|
+
|
34
|
+
to_return = { mtks: [] }
|
35
|
+
uniques.each do |key, value|
|
36
|
+
to_return[:mtks] << {
|
37
|
+
f: key,
|
38
|
+
ks: value.to_a
|
39
|
+
}
|
40
|
+
end
|
41
|
+
|
42
|
+
to_return
|
43
|
+
rescue StandardError => error
|
44
|
+
@config.log_found_exception(__method__.to_s, error)
|
45
|
+
nil
|
46
|
+
end
|
47
|
+
|
48
|
+
def impressions_count_formatter(counts)
|
49
|
+
return if counts.nil? || counts.empty?
|
50
|
+
|
51
|
+
formated_counts = {pf: []}
|
52
|
+
|
53
|
+
counts.each do |key, value|
|
54
|
+
key_splited = key.split('::')
|
55
|
+
|
56
|
+
formated_counts[:pf] << {
|
57
|
+
f: key_splited[0].to_s, # feature name
|
58
|
+
m: key_splited[1].to_i, # time frame
|
59
|
+
rc: value # count
|
60
|
+
}
|
61
|
+
end
|
62
|
+
|
63
|
+
formated_counts
|
64
|
+
rescue StandardError => error
|
65
|
+
@config.log_found_exception(__method__.to_s, error)
|
66
|
+
nil
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module SplitIoClient
|
4
|
+
module Cache
|
5
|
+
module Senders
|
6
|
+
class RedisImpressionsSender < ImpressionsSenderAdapter
|
7
|
+
EXPIRE_SECONDS = 3600
|
8
|
+
|
9
|
+
def initialize(config)
|
10
|
+
@config = config
|
11
|
+
@adapter = @config.impressions_adapter
|
12
|
+
end
|
13
|
+
|
14
|
+
def record_uniques_key(uniques)
|
15
|
+
formatted = uniques_formatter(uniques)
|
16
|
+
|
17
|
+
unless formatted.nil?
|
18
|
+
size = @adapter.add_to_queue(unique_keys_key, formatted)
|
19
|
+
@adapter.expire(unique_keys_key, EXPIRE_SECONDS) if formatted.size == size
|
20
|
+
end
|
21
|
+
rescue StandardError => e
|
22
|
+
@config.log_found_exception(__method__.to_s, e)
|
23
|
+
end
|
24
|
+
|
25
|
+
def record_impressions_count(impressions_count)
|
26
|
+
return if impressions_count.nil? || impressions_count.empty?
|
27
|
+
|
28
|
+
result = @adapter.redis.pipelined do |pipeline|
|
29
|
+
impressions_count.each do |key, value|
|
30
|
+
pipeline.hincrby(impressions_count_key, key, value)
|
31
|
+
end
|
32
|
+
|
33
|
+
@future = pipeline.hlen(impressions_count_key)
|
34
|
+
end
|
35
|
+
|
36
|
+
expire_impressions_count_key(impressions_count, result)
|
37
|
+
rescue StandardError => e
|
38
|
+
@config.log_found_exception(__method__.to_s, e)
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
def expire_impressions_count_key(impressions_count, pipeline_result)
|
44
|
+
total_count = impressions_count.sum { |_, value| value }
|
45
|
+
hlen = pipeline_result.last
|
46
|
+
|
47
|
+
@adapter.expire(impressions_count_key, EXPIRE_SECONDS) if impressions_count.size == hlen && (pipeline_result.sum - hlen) == total_count
|
48
|
+
end
|
49
|
+
|
50
|
+
def impressions_count_key
|
51
|
+
"#{@config.redis_namespace}.impressions.count"
|
52
|
+
end
|
53
|
+
|
54
|
+
def unique_keys_key
|
55
|
+
"#{@config.redis_namespace}.uniquekeys"
|
56
|
+
end
|
57
|
+
|
58
|
+
def uniques_formatter(uniques)
|
59
|
+
return if uniques.nil? || uniques.empty?
|
60
|
+
|
61
|
+
to_return = []
|
62
|
+
uniques.each do |key, value|
|
63
|
+
to_return << {
|
64
|
+
f: key,
|
65
|
+
k: value.to_a
|
66
|
+
}
|
67
|
+
end
|
68
|
+
|
69
|
+
to_return
|
70
|
+
rescue StandardError => error
|
71
|
+
@config.log_found_exception(__method__.to_s, error)
|
72
|
+
nil
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -4,12 +4,10 @@ module SplitIoClient
|
|
4
4
|
module Cache
|
5
5
|
module Senders
|
6
6
|
class ImpressionsCountSender
|
7
|
-
|
8
|
-
|
9
|
-
def initialize(config, impression_counter, impressions_api)
|
7
|
+
def initialize(config, impression_counter, impressions_sender_adapter)
|
10
8
|
@config = config
|
11
9
|
@impression_counter = impression_counter
|
12
|
-
@
|
10
|
+
@impressions_sender_adapter = impressions_sender_adapter
|
13
11
|
end
|
14
12
|
|
15
13
|
def call
|
@@ -22,13 +20,11 @@ module SplitIoClient
|
|
22
20
|
@config.threads[:impressions_count_sender] = Thread.new do
|
23
21
|
begin
|
24
22
|
@config.logger.info('Starting impressions count service')
|
25
|
-
|
26
23
|
loop do
|
27
|
-
|
28
|
-
|
29
|
-
sleep(COUNTER_REFRESH_RATE_SECONDS)
|
24
|
+
sleep(@config.counter_refresh_rate)
|
25
|
+
post_impressions_count
|
30
26
|
end
|
31
|
-
rescue SplitIoClient::SDKShutdownException
|
27
|
+
rescue SplitIoClient::SDKShutdownException
|
32
28
|
post_impressions_count
|
33
29
|
|
34
30
|
@config.logger.info('Posting impressions count due to shutdown')
|
@@ -37,27 +33,7 @@ module SplitIoClient
|
|
37
33
|
end
|
38
34
|
|
39
35
|
def post_impressions_count
|
40
|
-
@
|
41
|
-
rescue StandardError => error
|
42
|
-
@config.log_found_exception(__method__.to_s, error)
|
43
|
-
end
|
44
|
-
|
45
|
-
def formatter(counts)
|
46
|
-
return if counts.empty?
|
47
|
-
|
48
|
-
formated_counts = {pf: []}
|
49
|
-
|
50
|
-
counts.each do |key, value|
|
51
|
-
key_splited = key.split('::')
|
52
|
-
|
53
|
-
formated_counts[:pf] << {
|
54
|
-
f: key_splited[0].to_s, # feature name
|
55
|
-
m: key_splited[1].to_i, # time frame
|
56
|
-
rc: value # count
|
57
|
-
}
|
58
|
-
end
|
59
|
-
|
60
|
-
formated_counts
|
36
|
+
@impressions_sender_adapter.record_impressions_count(@impression_counter.pop_all)
|
61
37
|
rescue StandardError => error
|
62
38
|
@config.log_found_exception(__method__.to_s, error)
|
63
39
|
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module SplitIoClient
|
4
|
+
module Cache
|
5
|
+
module Senders
|
6
|
+
class ImpressionsSenderAdapter
|
7
|
+
extend Forwardable
|
8
|
+
def_delegators :@sender, :record_uniques_key, :record_impressions_count
|
9
|
+
|
10
|
+
def initialize(config, telemetry_api, impressions_api)
|
11
|
+
@sender = case config.telemetry_adapter.class.to_s
|
12
|
+
when 'SplitIoClient::Cache::Adapters::RedisAdapter'
|
13
|
+
Cache::Senders::RedisImpressionsSender.new(config)
|
14
|
+
else
|
15
|
+
Cache::Senders::MemoryImpressionsSender.new(config, telemetry_api, impressions_api)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -17,6 +17,14 @@ module SplitIoClient
|
|
17
17
|
post_telemetry("#{@config.telemetry_service_url}/metrics/usage", stats, 'stats')
|
18
18
|
end
|
19
19
|
|
20
|
+
def record_unique_keys(uniques)
|
21
|
+
return if uniques[:mtks].empty?
|
22
|
+
|
23
|
+
post_telemetry("#{@config.telemetry_service_url}/mtks/ss", uniques, 'mtks')
|
24
|
+
rescue StandardError => e
|
25
|
+
@config.log_found_exception(__method__.to_s, e)
|
26
|
+
end
|
27
|
+
|
20
28
|
private
|
21
29
|
|
22
30
|
def post_telemetry(url, obj, method)
|
@@ -4,65 +4,75 @@ module SplitIoClient
|
|
4
4
|
module Engine
|
5
5
|
module Common
|
6
6
|
class ImpressionManager
|
7
|
-
def initialize(config,
|
7
|
+
def initialize(config,
|
8
|
+
impressions_repository,
|
9
|
+
impression_counter,
|
10
|
+
telemetry_runtime_producer,
|
11
|
+
impression_observer,
|
12
|
+
unique_keys_tracker,
|
13
|
+
impression_router)
|
8
14
|
@config = config
|
9
15
|
@impressions_repository = impressions_repository
|
10
16
|
@impression_counter = impression_counter
|
11
|
-
@impression_observer =
|
17
|
+
@impression_observer = impression_observer
|
12
18
|
@telemetry_runtime_producer = telemetry_runtime_producer
|
19
|
+
@unique_keys_tracker = unique_keys_tracker
|
20
|
+
@impression_router = impression_router
|
13
21
|
end
|
14
22
|
|
15
|
-
# added param time for test
|
16
23
|
def build_impression(matching_key, bucketing_key, split_name, treatment, params = {})
|
17
24
|
impression_data = impression_data(matching_key, bucketing_key, split_name, treatment, params[:time])
|
18
25
|
|
19
|
-
|
20
|
-
|
21
|
-
|
26
|
+
begin
|
27
|
+
case @config.impressions_mode
|
28
|
+
when :debug # In DEBUG mode we should calculate the pt only.
|
29
|
+
impression_data[:pt] = @impression_observer.test_and_set(impression_data)
|
30
|
+
when :none # In NONE mode we should track the total amount of evaluations and the unique keys.
|
31
|
+
@impression_counter.inc(split_name, impression_data[:m])
|
32
|
+
@unique_keys_tracker.track(split_name, matching_key)
|
33
|
+
else # In OPTIMIZED mode we should track the total amount of evaluations and deduplicate the impressions.
|
34
|
+
impression_data[:pt] = @impression_observer.test_and_set(impression_data)
|
35
|
+
@impression_counter.inc(split_name, impression_data[:m])
|
36
|
+
end
|
37
|
+
rescue StandardError => e
|
38
|
+
@config.log_found_exception(__method__.to_s, e)
|
39
|
+
end
|
22
40
|
|
23
41
|
impression(impression_data, params[:attributes])
|
24
|
-
rescue StandardError => e
|
25
|
-
@config.log_found_exception(__method__.to_s, e)
|
26
42
|
end
|
27
43
|
|
28
44
|
def track(impressions)
|
29
45
|
return if impressions.empty?
|
30
46
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
unless optimized_impressions.empty?
|
41
|
-
dropped = @impressions_repository.add_bulk(optimized_impressions)
|
42
|
-
dedupe = impressions.length - optimized_impressions.length
|
43
|
-
queued = optimized_impressions.length - dropped
|
47
|
+
stats = { dropped: 0, queued: 0, dedupe: 0 }
|
48
|
+
begin
|
49
|
+
case @config.impressions_mode
|
50
|
+
when :none
|
51
|
+
return
|
52
|
+
when :debug
|
53
|
+
track_debug_mode(impressions, stats)
|
54
|
+
when :optimized
|
55
|
+
track_optimized_mode(impressions, stats)
|
44
56
|
end
|
45
|
-
|
46
|
-
|
47
|
-
|
57
|
+
rescue StandardError => e
|
58
|
+
@config.log_found_exception(__method__.to_s, e)
|
59
|
+
ensure
|
60
|
+
record_stats(stats)
|
61
|
+
@impression_router.add_bulk(impressions)
|
48
62
|
end
|
49
|
-
|
50
|
-
record_stats(queued, dropped, dedupe)
|
51
|
-
rescue StandardError => e
|
52
|
-
@config.log_found_exception(__method__.to_s, e)
|
53
63
|
end
|
54
64
|
|
55
65
|
private
|
56
66
|
|
57
|
-
def record_stats(
|
67
|
+
def record_stats(stats)
|
58
68
|
return if redis?
|
59
69
|
|
60
70
|
imp_queued = Telemetry::Domain::Constants::IMPRESSIONS_QUEUED
|
61
71
|
imp_dropped = Telemetry::Domain::Constants::IMPRESSIONS_DROPPED
|
62
72
|
imp_dedupe = Telemetry::Domain::Constants::IMPRESSIONS_DEDUPE
|
63
|
-
@telemetry_runtime_producer.record_impressions_stats(imp_queued, queued) unless queued.zero?
|
64
|
-
@telemetry_runtime_producer.record_impressions_stats(imp_dropped, dropped) unless dropped.zero?
|
65
|
-
@telemetry_runtime_producer.record_impressions_stats(imp_dedupe, dedupe) unless dedupe.zero?
|
73
|
+
@telemetry_runtime_producer.record_impressions_stats(imp_queued, stats[:queued]) unless stats[:queued].zero?
|
74
|
+
@telemetry_runtime_producer.record_impressions_stats(imp_dropped, stats[:dropped]) unless stats[:dropped].zero?
|
75
|
+
@telemetry_runtime_producer.record_impressions_stats(imp_dedupe, stats[:dedupe]) unless stats[:dedupe].zero?
|
66
76
|
end
|
67
77
|
|
68
78
|
# added param time for test
|
@@ -91,10 +101,6 @@ module SplitIoClient
|
|
91
101
|
@config.labels_enabled ? label : nil
|
92
102
|
end
|
93
103
|
|
94
|
-
def optimized?
|
95
|
-
@config.impressions_mode == :optimized
|
96
|
-
end
|
97
|
-
|
98
104
|
def should_queue_impression?(impression)
|
99
105
|
impression[:pt].nil? ||
|
100
106
|
(ImpressionCounter.truncate_time_frame(impression[:pt]) != ImpressionCounter.truncate_time_frame(impression[:m]))
|
@@ -108,10 +114,19 @@ module SplitIoClient
|
|
108
114
|
@config.impressions_adapter.class.to_s == 'SplitIoClient::Cache::Adapters::RedisAdapter'
|
109
115
|
end
|
110
116
|
|
111
|
-
def
|
112
|
-
|
113
|
-
|
114
|
-
|
117
|
+
def track_debug_mode(impressions, stats)
|
118
|
+
stats[:dropped] = @impressions_repository.add_bulk(impressions)
|
119
|
+
stats[:queued] = impressions.length - stats[:dropped]
|
120
|
+
end
|
121
|
+
|
122
|
+
def track_optimized_mode(impressions, stats)
|
123
|
+
optimized_impressions = impressions.select { |imp| should_queue_impression?(imp[:i]) }
|
124
|
+
|
125
|
+
return if optimized_impressions.empty?
|
126
|
+
|
127
|
+
stats[:dropped] = @impressions_repository.add_bulk(optimized_impressions)
|
128
|
+
stats[:dedupe] = impressions.length - optimized_impressions.length
|
129
|
+
stats[:queued] = optimized_impressions.length - stats[:dropped]
|
115
130
|
end
|
116
131
|
end
|
117
132
|
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'concurrent'
|
4
|
+
|
5
|
+
module SplitIoClient
|
6
|
+
module Engine
|
7
|
+
module Common
|
8
|
+
class NoopImpressionCounter
|
9
|
+
def inc(split_name, time_frame)
|
10
|
+
# no-op
|
11
|
+
end
|
12
|
+
|
13
|
+
def pop_all
|
14
|
+
# no-op
|
15
|
+
end
|
16
|
+
|
17
|
+
def make_key(split_name, time_frame)
|
18
|
+
# no-op
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.truncate_time_frame(timestamp_ms)
|
22
|
+
# no-op
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module SplitIoClient
|
4
|
+
module Engine
|
5
|
+
module Impressions
|
6
|
+
class UniqueKeysTracker
|
7
|
+
INTERVAL_TO_CLEAR_LONG_TERM_CACHE = 86_400 # 24 hours
|
8
|
+
|
9
|
+
def initialize(config,
|
10
|
+
filter_adapter,
|
11
|
+
sender_adapter,
|
12
|
+
cache)
|
13
|
+
@config = config
|
14
|
+
@filter_adapter = filter_adapter
|
15
|
+
@sender_adapter = sender_adapter
|
16
|
+
@cache = cache
|
17
|
+
@cache_max_size = config.unique_keys_cache_max_size
|
18
|
+
@max_bulk_size = config.unique_keys_bulk_size
|
19
|
+
@semaphore = Mutex.new
|
20
|
+
end
|
21
|
+
|
22
|
+
def call
|
23
|
+
@config.threads[:unique_keys_sender] = Thread.new { send_bulk_data_thread }
|
24
|
+
@config.threads[:clear_filter] = Thread.new { clear_filter_thread }
|
25
|
+
end
|
26
|
+
|
27
|
+
def track(feature_name, key)
|
28
|
+
return false if @filter_adapter.contains?(feature_name, key)
|
29
|
+
|
30
|
+
@filter_adapter.add(feature_name, key)
|
31
|
+
|
32
|
+
add_or_update(feature_name, key)
|
33
|
+
|
34
|
+
send_bulk_data if @cache.size >= @cache_max_size
|
35
|
+
|
36
|
+
true
|
37
|
+
rescue StandardError => e
|
38
|
+
@config.log_found_exception(__method__.to_s, e)
|
39
|
+
false
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
def send_bulk_data_thread
|
45
|
+
@config.logger.info('Starting Unique Keys Tracker.') if @config.debug_enabled
|
46
|
+
loop do
|
47
|
+
sleep(@config.unique_keys_refresh_rate)
|
48
|
+
send_bulk_data
|
49
|
+
end
|
50
|
+
rescue SplitIoClient::SDKShutdownException
|
51
|
+
send_bulk_data
|
52
|
+
@config.logger.info('Posting unique keys due to shutdown')
|
53
|
+
end
|
54
|
+
|
55
|
+
def clear_filter_thread
|
56
|
+
loop do
|
57
|
+
sleep(INTERVAL_TO_CLEAR_LONG_TERM_CACHE)
|
58
|
+
@config.logger.debug('Starting task to clean the filter cache.') if @config.debug_enabled
|
59
|
+
@filter_adapter.clear
|
60
|
+
end
|
61
|
+
rescue SplitIoClient::SDKShutdownException
|
62
|
+
@filter_adapter.clear
|
63
|
+
end
|
64
|
+
|
65
|
+
def add_or_update(feature_name, key)
|
66
|
+
if @cache[feature_name].nil?
|
67
|
+
@cache[feature_name] = Set.new([key])
|
68
|
+
else
|
69
|
+
@cache[feature_name].add(key)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def send_bulk_data
|
74
|
+
@semaphore.synchronize do
|
75
|
+
return if @cache.empty?
|
76
|
+
|
77
|
+
uniques = @cache.clone
|
78
|
+
@cache.clear
|
79
|
+
|
80
|
+
if uniques.size <= @max_bulk_size
|
81
|
+
@sender_adapter.record_uniques_key(uniques)
|
82
|
+
return
|
83
|
+
end
|
84
|
+
|
85
|
+
bulks = SplitIoClient::Utilities.split_bulk_to_send(uniques, uniques.size / @max_bulk_size)
|
86
|
+
|
87
|
+
bulks.each do |b|
|
88
|
+
@sender_adapter.record_uniques_key(b)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
rescue StandardError => e
|
92
|
+
@config.log_found_exception(__method__.to_s, e)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
@@ -52,9 +52,8 @@ module SplitIoClient
|
|
52
52
|
# @return [boolean] match value for combiner delegates
|
53
53
|
def eval_and(args)
|
54
54
|
# Convert all keys to symbols
|
55
|
-
if args && args[:attributes]
|
56
|
-
|
57
|
-
end
|
55
|
+
args[:attributes] = args[:attributes].each_with_object({}) { |(k, v), memo| memo[k.to_sym] = v } if args && args[:attributes]
|
56
|
+
|
58
57
|
@matchers.all? do |matcher|
|
59
58
|
if match_with_key?(matcher)
|
60
59
|
matcher.match?(value: args[:matching_key])
|
@@ -30,6 +30,11 @@ module SplitIoClient
|
|
30
30
|
PhusionPassenger.on_event(:starting_worker_process) { |forked| start_thread if forked } if defined?(PhusionPassenger)
|
31
31
|
end
|
32
32
|
|
33
|
+
def start_consumer
|
34
|
+
start_consumer_thread
|
35
|
+
PhusionPassenger.on_event(:starting_worker_process) { |forked| start_consumer_thread if forked } if defined?(PhusionPassenger)
|
36
|
+
end
|
37
|
+
|
33
38
|
private
|
34
39
|
|
35
40
|
def start_thread
|
@@ -55,6 +60,14 @@ module SplitIoClient
|
|
55
60
|
end
|
56
61
|
end
|
57
62
|
|
63
|
+
def start_consumer_thread
|
64
|
+
@config.threads[:start_sdk_consumer] = Thread.new do
|
65
|
+
@status_manager.ready!
|
66
|
+
@telemetry_synchronizer.synchronize_config
|
67
|
+
@synchronizer.start_periodic_data_recording
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
58
71
|
def process_subsystem_ready
|
59
72
|
@synchronizer.stop_periodic_fetch
|
60
73
|
@synchronizer.sync_all
|
@@ -12,7 +12,6 @@ module SplitIoClient
|
|
12
12
|
|
13
13
|
def initialize(
|
14
14
|
repositories,
|
15
|
-
api_key,
|
16
15
|
config,
|
17
16
|
params
|
18
17
|
)
|
@@ -20,13 +19,14 @@ module SplitIoClient
|
|
20
19
|
@segments_repository = repositories[:segments]
|
21
20
|
@impressions_repository = repositories[:impressions]
|
22
21
|
@events_repository = repositories[:events]
|
23
|
-
@api_key = api_key
|
24
22
|
@config = config
|
25
23
|
@split_fetcher = params[:split_fetcher]
|
26
24
|
@segment_fetcher = params[:segment_fetcher]
|
27
|
-
@impressions_api =
|
25
|
+
@impressions_api = params[:impressions_api]
|
28
26
|
@impression_counter = params[:imp_counter]
|
29
27
|
@telemetry_synchronizer = params[:telemetry_synchronizer]
|
28
|
+
@impressions_sender_adapter = params[:impressions_sender_adapter]
|
29
|
+
@unique_keys_tracker = params[:unique_keys_tracker]
|
30
30
|
end
|
31
31
|
|
32
32
|
def sync_all(asynchronous = true)
|
@@ -42,10 +42,14 @@ module SplitIoClient
|
|
42
42
|
end
|
43
43
|
|
44
44
|
def start_periodic_data_recording
|
45
|
-
|
46
|
-
|
45
|
+
unless @config.consumer?
|
46
|
+
impressions_sender
|
47
|
+
events_sender
|
48
|
+
start_telemetry_sync_task
|
49
|
+
end
|
50
|
+
|
47
51
|
impressions_count_sender
|
48
|
-
|
52
|
+
start_unique_keys_tracker_task
|
49
53
|
end
|
50
54
|
|
51
55
|
def start_periodic_fetch
|
@@ -170,7 +174,7 @@ module SplitIoClient
|
|
170
174
|
|
171
175
|
# Starts thread which loops constantly and sends impressions to the Split API
|
172
176
|
def impressions_sender
|
173
|
-
ImpressionsSender.new(@impressions_repository, @config, @impressions_api).call
|
177
|
+
ImpressionsSender.new(@impressions_repository, @config, @impressions_api).call unless @config.impressions_mode == :none
|
174
178
|
end
|
175
179
|
|
176
180
|
# Starts thread which loops constantly and sends events to the Split API
|
@@ -180,13 +184,17 @@ module SplitIoClient
|
|
180
184
|
|
181
185
|
# Starts thread which loops constantly and sends impressions count to the Split API
|
182
186
|
def impressions_count_sender
|
183
|
-
ImpressionsCountSender.new(@config, @impression_counter, @
|
187
|
+
ImpressionsCountSender.new(@config, @impression_counter, @impressions_sender_adapter).call unless @config.impressions_mode == :debug
|
184
188
|
end
|
185
189
|
|
186
190
|
def start_telemetry_sync_task
|
187
191
|
Telemetry::SyncTask.new(@config, @telemetry_synchronizer).call
|
188
192
|
end
|
189
193
|
|
194
|
+
def start_unique_keys_tracker_task
|
195
|
+
@unique_keys_tracker.call
|
196
|
+
end
|
197
|
+
|
190
198
|
def sync_result(success, remaining_attempts, segment_names = nil)
|
191
199
|
{ success: success, remaining_attempts: remaining_attempts, segment_names: segment_names }
|
192
200
|
end
|
@@ -111,6 +111,12 @@ module SplitIoClient
|
|
111
111
|
@telemetry_refresh_rate = SplitConfig.init_telemetry_refresh_rate(opts[:telemetry_refresh_rate])
|
112
112
|
@telemetry_service_url = opts[:telemetry_service_url] || SplitConfig.default_telemetry_service_url
|
113
113
|
|
114
|
+
@unique_keys_refresh_rate = SplitConfig.default_unique_keys_refresh_rate(@cache_adapter)
|
115
|
+
@unique_keys_cache_max_size = SplitConfig.default_unique_keys_cache_max_size
|
116
|
+
@unique_keys_bulk_size = SplitConfig.default_unique_keys_bulk_size(@cache_adapter)
|
117
|
+
|
118
|
+
@counter_refresh_rate = SplitConfig.default_counter_refresh_rate(@cache_adapter)
|
119
|
+
|
114
120
|
@sdk_start_time = Time.now
|
115
121
|
|
116
122
|
@on_demand_fetch_retry_delay_seconds = SplitConfig.default_on_demand_fetch_retry_delay_seconds
|
@@ -284,6 +290,18 @@ module SplitIoClient
|
|
284
290
|
attr_accessor :on_demand_fetch_retry_delay_seconds
|
285
291
|
attr_accessor :on_demand_fetch_max_retries
|
286
292
|
|
293
|
+
attr_accessor :unique_keys_refresh_rate
|
294
|
+
attr_accessor :unique_keys_cache_max_size
|
295
|
+
attr_accessor :unique_keys_bulk_size
|
296
|
+
|
297
|
+
attr_accessor :counter_refresh_rate
|
298
|
+
|
299
|
+
def self.default_counter_refresh_rate(adapter)
|
300
|
+
return 300 if adapter == :redis # Send bulk impressions count - Refresh rate: 5 min.
|
301
|
+
|
302
|
+
1800 # Send bulk impressions count - Refresh rate: 30 min.
|
303
|
+
end
|
304
|
+
|
287
305
|
def self.default_on_demand_fetch_retry_delay_seconds
|
288
306
|
0.05
|
289
307
|
end
|
@@ -302,6 +320,8 @@ module SplitIoClient
|
|
302
320
|
case impressions_mode
|
303
321
|
when :debug
|
304
322
|
return :debug
|
323
|
+
when :none
|
324
|
+
return :none
|
305
325
|
else
|
306
326
|
@logger.error('You passed an invalid impressions_mode, impressions_mode should be one of the following values: :debug or :optimized. Defaulting to :optimized mode') unless impressions_mode == :optimized
|
307
327
|
return :optimized
|
@@ -468,6 +488,22 @@ module SplitIoClient
|
|
468
488
|
3600
|
469
489
|
end
|
470
490
|
|
491
|
+
def self.default_unique_keys_refresh_rate(adapter)
|
492
|
+
return 300 if adapter == :redis
|
493
|
+
|
494
|
+
900
|
495
|
+
end
|
496
|
+
|
497
|
+
def self.default_unique_keys_cache_max_size
|
498
|
+
30000
|
499
|
+
end
|
500
|
+
|
501
|
+
def self.default_unique_keys_bulk_size(adapter)
|
502
|
+
return 2000 if adapter == :redis
|
503
|
+
|
504
|
+
5000
|
505
|
+
end
|
506
|
+
|
471
507
|
def self.default_telemetry_service_url
|
472
508
|
'https://telemetry.split.io/api/v1'
|
473
509
|
end
|
@@ -1,3 +1,7 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'bloomfilter-rb'
|
4
|
+
|
1
5
|
module SplitIoClient
|
2
6
|
class SplitFactory
|
3
7
|
ROOT_PROCESS_ID = Process.pid
|
@@ -34,8 +38,10 @@ module SplitIoClient
|
|
34
38
|
|
35
39
|
build_telemetry_components
|
36
40
|
build_repositories
|
37
|
-
build_impressions_components
|
38
41
|
build_telemetry_synchronizer
|
42
|
+
build_impressions_sender_adapter
|
43
|
+
build_unique_keys_tracker
|
44
|
+
build_impressions_components
|
39
45
|
|
40
46
|
@status_manager = Engine::StatusManager.new(@config)
|
41
47
|
|
@@ -49,8 +55,10 @@ module SplitIoClient
|
|
49
55
|
return start_localhost_components if @config.localhost_mode
|
50
56
|
|
51
57
|
if @config.consumer?
|
52
|
-
|
53
|
-
|
58
|
+
build_synchronizer
|
59
|
+
build_sync_manager
|
60
|
+
|
61
|
+
@sync_manager.start_consumer
|
54
62
|
return
|
55
63
|
end
|
56
64
|
|
@@ -167,11 +175,13 @@ module SplitIoClient
|
|
167
175
|
split_fetcher: @split_fetcher,
|
168
176
|
segment_fetcher: @segment_fetcher,
|
169
177
|
imp_counter: @impression_counter,
|
170
|
-
|
171
|
-
|
178
|
+
telemetry_synchronizer: @telemetry_synchronizer,
|
179
|
+
impressions_sender_adapter: @impressions_sender_adapter,
|
180
|
+
impressions_api: @impressions_api,
|
181
|
+
unique_keys_tracker: @unique_keys_tracker
|
172
182
|
}
|
173
183
|
|
174
|
-
@synchronizer = Engine::Synchronizer.new(repositories, @
|
184
|
+
@synchronizer = Engine::Synchronizer.new(repositories, @config, params)
|
175
185
|
end
|
176
186
|
|
177
187
|
def build_streaming_components
|
@@ -198,13 +208,51 @@ module SplitIoClient
|
|
198
208
|
end
|
199
209
|
|
200
210
|
def build_telemetry_synchronizer
|
201
|
-
telemetry_api = Api::TelemetryApi.new(@config, @api_key, @runtime_producer)
|
202
|
-
@telemetry_synchronizer = Telemetry::Synchronizer.new(@config, @telemetry_consumers, @init_producer, repositories, telemetry_api)
|
211
|
+
@telemetry_api = Api::TelemetryApi.new(@config, @api_key, @runtime_producer)
|
212
|
+
@telemetry_synchronizer = Telemetry::Synchronizer.new(@config, @telemetry_consumers, @init_producer, repositories, @telemetry_api)
|
213
|
+
end
|
214
|
+
|
215
|
+
def build_unique_keys_tracker
|
216
|
+
if @config.impressions_mode != :none
|
217
|
+
@unique_keys_tracker = Engine::Impressions::NoopUniqueKeysTracker.new
|
218
|
+
return
|
219
|
+
end
|
220
|
+
|
221
|
+
bf = BloomFilter::Native.new(size: 95_850_584, hashes: 2)
|
222
|
+
filter_adapter = Cache::Filter::FilterAdapter.new(@config, bf)
|
223
|
+
cache = Concurrent::Hash.new
|
224
|
+
@unique_keys_tracker = Engine::Impressions::UniqueKeysTracker.new(@config, filter_adapter, @impressions_sender_adapter, cache)
|
225
|
+
end
|
226
|
+
|
227
|
+
def build_impressions_observer
|
228
|
+
if (@config.cache_adapter == :redis && @config.impressions_mode != :optimized) ||
|
229
|
+
(@config.cache_adapter == :memory && @config.impressions_mode == :none)
|
230
|
+
@impression_observer = Observers::NoopImpressionObserver.new
|
231
|
+
else
|
232
|
+
@impression_observer = Observers::ImpressionObserver.new
|
233
|
+
end
|
234
|
+
end
|
235
|
+
|
236
|
+
def build_impression_counter
|
237
|
+
case @config.impressions_mode
|
238
|
+
when :debug
|
239
|
+
@impression_counter = Engine::Common::NoopImpressionCounter.new
|
240
|
+
else
|
241
|
+
@impression_counter = Engine::Common::ImpressionCounter.new
|
242
|
+
end
|
243
|
+
end
|
244
|
+
|
245
|
+
def build_impressions_sender_adapter
|
246
|
+
@impressions_api = Api::Impressions.new(@api_key, @config, @runtime_producer)
|
247
|
+
@impressions_sender_adapter = Cache::Senders::ImpressionsSenderAdapter.new(@config, @telemetry_api, @impressions_api)
|
203
248
|
end
|
204
249
|
|
205
250
|
def build_impressions_components
|
206
|
-
|
207
|
-
|
251
|
+
build_impressions_observer
|
252
|
+
build_impression_counter
|
253
|
+
|
254
|
+
impression_router = ImpressionRouter.new(@config)
|
255
|
+
@impressions_manager = Engine::Common::ImpressionManager.new(@config, @impressions_repository, @impression_counter, @runtime_producer, @impression_observer, @unique_keys_tracker, impression_router)
|
208
256
|
end
|
209
257
|
end
|
210
258
|
end
|
@@ -37,5 +37,17 @@ module SplitIoClient
|
|
37
37
|
|
38
38
|
interval * random_factor
|
39
39
|
end
|
40
|
+
|
41
|
+
def split_bulk_to_send(hash, divisions)
|
42
|
+
count = 0
|
43
|
+
|
44
|
+
hash.each_with_object([]) do |key_value, final|
|
45
|
+
final[count % divisions] ||= {}
|
46
|
+
final[count % divisions][key_value[0]] = key_value[1]
|
47
|
+
count += 1
|
48
|
+
end
|
49
|
+
rescue StandardError
|
50
|
+
[]
|
51
|
+
end
|
40
52
|
end
|
41
53
|
end
|
data/lib/splitclient-rb.rb
CHANGED
@@ -12,8 +12,10 @@ require 'splitclient-rb/cache/adapters/memory_adapter'
|
|
12
12
|
require 'splitclient-rb/cache/adapters/redis_adapter'
|
13
13
|
require 'splitclient-rb/cache/fetchers/segment_fetcher'
|
14
14
|
require 'splitclient-rb/cache/fetchers/split_fetcher'
|
15
|
+
require 'splitclient-rb/cache/filter/filter_adapter'
|
15
16
|
require 'splitclient-rb/cache/hashers/impression_hasher'
|
16
17
|
require 'splitclient-rb/cache/observers/impression_observer'
|
18
|
+
require 'splitclient-rb/cache/observers/noop_impression_observer'
|
17
19
|
require 'splitclient-rb/cache/repositories/repository'
|
18
20
|
require 'splitclient-rb/cache/repositories/segments_repository'
|
19
21
|
require 'splitclient-rb/cache/repositories/splits_repository'
|
@@ -28,6 +30,9 @@ require 'splitclient-rb/cache/senders/impressions_sender'
|
|
28
30
|
require 'splitclient-rb/cache/senders/events_sender'
|
29
31
|
require 'splitclient-rb/cache/senders/impressions_count_sender'
|
30
32
|
require 'splitclient-rb/cache/senders/localhost_repo_cleaner'
|
33
|
+
require 'splitclient-rb/cache/senders/impressions_sender_adapter'
|
34
|
+
require 'splitclient-rb/cache/senders/impressions_adapter/memory_sender'
|
35
|
+
require 'splitclient-rb/cache/senders/impressions_adapter/redis_sender'
|
31
36
|
require 'splitclient-rb/cache/stores/localhost_split_builder'
|
32
37
|
require 'splitclient-rb/cache/stores/localhost_split_store'
|
33
38
|
require 'splitclient-rb/cache/stores/store_utils'
|
@@ -52,6 +57,7 @@ require 'splitclient-rb/engine/api/events'
|
|
52
57
|
require 'splitclient-rb/engine/api/telemetry_api'
|
53
58
|
require 'splitclient-rb/engine/common/impressions_counter'
|
54
59
|
require 'splitclient-rb/engine/common/impressions_manager'
|
60
|
+
require 'splitclient-rb/engine/common/noop_impressions_counter'
|
55
61
|
require 'splitclient-rb/engine/parser/condition'
|
56
62
|
require 'splitclient-rb/engine/parser/partition'
|
57
63
|
require 'splitclient-rb/engine/parser/evaluator'
|
@@ -79,6 +85,8 @@ require 'splitclient-rb/engine/matchers/equal_to_boolean_matcher'
|
|
79
85
|
require 'splitclient-rb/engine/matchers/equal_to_matcher'
|
80
86
|
require 'splitclient-rb/engine/matchers/matches_string_matcher'
|
81
87
|
require 'splitclient-rb/engine/evaluator/splitter'
|
88
|
+
require 'splitclient-rb/engine/impressions/noop_unique_keys_tracker'
|
89
|
+
require 'splitclient-rb/engine/impressions/unique_keys_tracker'
|
82
90
|
require 'splitclient-rb/engine/metrics/binary_search_latency_tracker'
|
83
91
|
require 'splitclient-rb/engine/models/split'
|
84
92
|
require 'splitclient-rb/engine/models/label'
|
data/splitclient-rb.gemspec
CHANGED
@@ -50,6 +50,7 @@ Gem::Specification.new do |spec|
|
|
50
50
|
spec.add_development_dependency 'timecop', '~> 0.9'
|
51
51
|
spec.add_development_dependency 'webmock', '~> 3.14'
|
52
52
|
|
53
|
+
spec.add_runtime_dependency 'bloomfilter-rb', '~> 2.1'
|
53
54
|
spec.add_runtime_dependency 'concurrent-ruby', '~> 1.0'
|
54
55
|
spec.add_runtime_dependency 'faraday', '>= 0.8', '< 2.0'
|
55
56
|
spec.add_runtime_dependency 'json', '>= 1.8', '< 3.0'
|
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: 7.3.
|
4
|
+
version: 7.3.5.pre.rc1
|
5
5
|
platform: java
|
6
6
|
authors:
|
7
7
|
- Split Software
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-
|
11
|
+
date: 2022-04-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
requirement: !ruby/object:Gem::Requirement
|
@@ -192,6 +192,20 @@ dependencies:
|
|
192
192
|
- - "~>"
|
193
193
|
- !ruby/object:Gem::Version
|
194
194
|
version: '3.14'
|
195
|
+
- !ruby/object:Gem::Dependency
|
196
|
+
requirement: !ruby/object:Gem::Requirement
|
197
|
+
requirements:
|
198
|
+
- - "~>"
|
199
|
+
- !ruby/object:Gem::Version
|
200
|
+
version: '2.1'
|
201
|
+
name: bloomfilter-rb
|
202
|
+
prerelease: false
|
203
|
+
type: :runtime
|
204
|
+
version_requirements: !ruby/object:Gem::Requirement
|
205
|
+
requirements:
|
206
|
+
- - "~>"
|
207
|
+
- !ruby/object:Gem::Version
|
208
|
+
version: '2.1'
|
195
209
|
- !ruby/object:Gem::Dependency
|
196
210
|
requirement: !ruby/object:Gem::Requirement
|
197
211
|
requirements:
|
@@ -363,6 +377,7 @@ extra_rdoc_files: []
|
|
363
377
|
files:
|
364
378
|
- ".github/pull_request_template.md"
|
365
379
|
- ".github/workflows/ci.yml"
|
380
|
+
- ".github/workflows/update-license-year.yml"
|
366
381
|
- ".gitignore"
|
367
382
|
- ".rubocop.yml"
|
368
383
|
- ".simplecov"
|
@@ -387,8 +402,10 @@ files:
|
|
387
402
|
- lib/splitclient-rb/cache/adapters/redis_adapter.rb
|
388
403
|
- lib/splitclient-rb/cache/fetchers/segment_fetcher.rb
|
389
404
|
- lib/splitclient-rb/cache/fetchers/split_fetcher.rb
|
405
|
+
- lib/splitclient-rb/cache/filter/filter_adapter.rb
|
390
406
|
- lib/splitclient-rb/cache/hashers/impression_hasher.rb
|
391
407
|
- lib/splitclient-rb/cache/observers/impression_observer.rb
|
408
|
+
- lib/splitclient-rb/cache/observers/noop_impression_observer.rb
|
392
409
|
- lib/splitclient-rb/cache/repositories/events/memory_repository.rb
|
393
410
|
- lib/splitclient-rb/cache/repositories/events/redis_repository.rb
|
394
411
|
- lib/splitclient-rb/cache/repositories/events_repository.rb
|
@@ -400,9 +417,12 @@ files:
|
|
400
417
|
- lib/splitclient-rb/cache/repositories/splits_repository.rb
|
401
418
|
- lib/splitclient-rb/cache/routers/impression_router.rb
|
402
419
|
- lib/splitclient-rb/cache/senders/events_sender.rb
|
420
|
+
- lib/splitclient-rb/cache/senders/impressions_adapter/memory_sender.rb
|
421
|
+
- lib/splitclient-rb/cache/senders/impressions_adapter/redis_sender.rb
|
403
422
|
- lib/splitclient-rb/cache/senders/impressions_count_sender.rb
|
404
423
|
- lib/splitclient-rb/cache/senders/impressions_formatter.rb
|
405
424
|
- lib/splitclient-rb/cache/senders/impressions_sender.rb
|
425
|
+
- lib/splitclient-rb/cache/senders/impressions_sender_adapter.rb
|
406
426
|
- lib/splitclient-rb/cache/senders/localhost_repo_cleaner.rb
|
407
427
|
- lib/splitclient-rb/cache/stores/localhost_split_builder.rb
|
408
428
|
- lib/splitclient-rb/cache/stores/localhost_split_store.rb
|
@@ -421,7 +441,10 @@ files:
|
|
421
441
|
- lib/splitclient-rb/engine/back_off.rb
|
422
442
|
- lib/splitclient-rb/engine/common/impressions_counter.rb
|
423
443
|
- lib/splitclient-rb/engine/common/impressions_manager.rb
|
444
|
+
- lib/splitclient-rb/engine/common/noop_impressions_counter.rb
|
424
445
|
- lib/splitclient-rb/engine/evaluator/splitter.rb
|
446
|
+
- lib/splitclient-rb/engine/impressions/noop_unique_keys_tracker.rb
|
447
|
+
- lib/splitclient-rb/engine/impressions/unique_keys_tracker.rb
|
425
448
|
- lib/splitclient-rb/engine/matchers/all_keys_matcher.rb
|
426
449
|
- lib/splitclient-rb/engine/matchers/between_matcher.rb
|
427
450
|
- lib/splitclient-rb/engine/matchers/combiners.rb
|