splitclient-rb 6.3.0 → 8.11.0
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/CODEOWNERS +1 -0
- data/.github/pull_request_template.md +9 -0
- data/.github/workflows/ci.yml +90 -0
- data/.github/workflows/update-license-year.yml +45 -0
- data/.gitignore +4 -0
- data/.rubocop.yml +46 -3
- data/CHANGES.txt +158 -11
- data/CONTRIBUTORS-GUIDE.md +49 -0
- data/LICENSE +169 -13
- data/NOTICE.txt +5 -0
- data/README.md +67 -27
- data/Rakefile +1 -8
- data/ext/murmurhash/3_x64_128.c +117 -0
- data/ext/murmurhash/murmurhash.c +5 -1
- data/lib/murmurhash/murmurhash.jar +0 -0
- data/lib/splitclient-rb/cache/adapters/cache_adapter.rb +3 -3
- data/lib/splitclient-rb/cache/adapters/memory_adapters/map_adapter.rb +4 -0
- data/lib/splitclient-rb/cache/adapters/memory_adapters/queue_adapter.rb +7 -0
- data/lib/splitclient-rb/cache/adapters/redis_adapter.rb +12 -4
- data/lib/splitclient-rb/cache/fetchers/segment_fetcher.rb +83 -0
- data/lib/splitclient-rb/cache/fetchers/split_fetcher.rb +70 -0
- data/lib/splitclient-rb/cache/filter/bloom_filter.rb +67 -0
- data/lib/splitclient-rb/cache/filter/filter_adapter.rb +32 -0
- data/lib/splitclient-rb/cache/filter/flag_set_filter.rb +40 -0
- data/lib/splitclient-rb/cache/hashers/impression_hasher.rb +34 -0
- data/lib/splitclient-rb/cache/observers/impression_observer.rb +22 -0
- data/lib/splitclient-rb/cache/observers/noop_impression_observer.rb +10 -0
- data/lib/splitclient-rb/cache/repositories/events/memory_repository.rb +26 -14
- data/lib/splitclient-rb/cache/repositories/events/redis_repository.rb +9 -14
- data/lib/splitclient-rb/cache/repositories/events_repository.rb +31 -10
- data/lib/splitclient-rb/cache/repositories/flag_sets/memory_repository.rb +40 -0
- data/lib/splitclient-rb/cache/repositories/flag_sets/redis_repository.rb +49 -0
- data/lib/splitclient-rb/cache/repositories/impressions/memory_repository.rb +22 -23
- data/lib/splitclient-rb/cache/repositories/impressions/redis_repository.rb +15 -22
- data/lib/splitclient-rb/cache/repositories/impressions_repository.rb +6 -31
- data/lib/splitclient-rb/cache/repositories/repository.rb +6 -5
- data/lib/splitclient-rb/cache/repositories/rule_based_segments_repository.rb +136 -0
- data/lib/splitclient-rb/cache/repositories/segments_repository.rb +46 -6
- data/lib/splitclient-rb/cache/repositories/splits_repository.rb +232 -43
- data/lib/splitclient-rb/cache/routers/impression_router.rb +24 -22
- data/lib/splitclient-rb/cache/senders/events_sender.rb +12 -29
- data/lib/splitclient-rb/cache/senders/impressions_adapter/memory_sender.rb +71 -0
- data/lib/splitclient-rb/cache/senders/impressions_adapter/redis_sender.rb +69 -0
- data/lib/splitclient-rb/cache/senders/impressions_count_sender.rb +43 -0
- data/lib/splitclient-rb/cache/senders/impressions_formatter.rb +27 -13
- data/lib/splitclient-rb/cache/senders/impressions_sender.rb +11 -25
- data/lib/splitclient-rb/cache/senders/impressions_sender_adapter.rb +21 -0
- data/lib/splitclient-rb/cache/senders/localhost_repo_cleaner.rb +47 -0
- data/lib/splitclient-rb/cache/stores/localhost_split_builder.rb +95 -0
- data/lib/splitclient-rb/cache/stores/localhost_split_store.rb +110 -0
- data/lib/splitclient-rb/cache/stores/store_utils.rb +13 -0
- data/lib/splitclient-rb/clients/split_client.rb +385 -138
- data/lib/splitclient-rb/constants.rb +16 -0
- data/lib/splitclient-rb/engine/api/client.rb +38 -43
- data/lib/splitclient-rb/engine/api/events.rb +19 -11
- data/lib/splitclient-rb/engine/api/faraday_middleware/gzip.rb +1 -0
- data/lib/splitclient-rb/engine/api/impressions.rb +49 -14
- data/lib/splitclient-rb/engine/api/segments.rb +31 -24
- data/lib/splitclient-rb/engine/api/splits.rb +108 -33
- data/lib/splitclient-rb/engine/api/telemetry_api.rb +47 -0
- data/lib/splitclient-rb/engine/auth_api_client.rb +96 -0
- data/lib/splitclient-rb/engine/back_off.rb +26 -0
- data/lib/splitclient-rb/engine/common/impressions_counter.rb +45 -0
- data/lib/splitclient-rb/engine/common/impressions_manager.rb +165 -0
- data/lib/splitclient-rb/engine/common/noop_impressions_counter.rb +27 -0
- data/lib/splitclient-rb/engine/events/events_delivery.rb +20 -0
- data/lib/splitclient-rb/engine/events/events_manager.rb +194 -0
- data/lib/splitclient-rb/engine/events/events_manager_config.rb +96 -0
- data/lib/splitclient-rb/engine/events/events_task.rb +50 -0
- data/lib/splitclient-rb/engine/events/noop_events_queue.rb +13 -0
- data/lib/splitclient-rb/engine/fallback_treatment_calculator.rb +48 -0
- data/lib/splitclient-rb/engine/impressions/noop_unique_keys_tracker.rb +17 -0
- data/lib/splitclient-rb/engine/impressions/unique_keys_tracker.rb +144 -0
- data/lib/splitclient-rb/engine/matchers/all_keys_matcher.rb +1 -1
- data/lib/splitclient-rb/engine/matchers/between_matcher.rb +7 -5
- data/lib/splitclient-rb/engine/matchers/between_semver_matcher.rb +33 -0
- data/lib/splitclient-rb/engine/matchers/combining_matcher.rb +10 -8
- data/lib/splitclient-rb/engine/matchers/contains_all_matcher.rb +2 -6
- data/lib/splitclient-rb/engine/matchers/contains_any_matcher.rb +1 -5
- data/lib/splitclient-rb/engine/matchers/contains_matcher.rb +7 -5
- data/lib/splitclient-rb/engine/matchers/dependency_matcher.rb +6 -5
- data/lib/splitclient-rb/engine/matchers/ends_with_matcher.rb +5 -4
- data/lib/splitclient-rb/engine/matchers/equal_to_boolean_matcher.rb +3 -2
- data/lib/splitclient-rb/engine/matchers/equal_to_matcher.rb +6 -4
- data/lib/splitclient-rb/engine/matchers/equal_to_semver_matcher.rb +28 -0
- data/lib/splitclient-rb/engine/matchers/equal_to_set_matcher.rb +1 -5
- data/lib/splitclient-rb/engine/matchers/greater_than_or_equal_to_matcher.rb +6 -4
- data/lib/splitclient-rb/engine/matchers/greater_than_or_equal_to_semver_matcher.rb +28 -0
- data/lib/splitclient-rb/engine/matchers/in_list_semver_matcher.rb +36 -0
- data/lib/splitclient-rb/engine/matchers/less_than_or_equal_to_matcher.rb +6 -4
- data/lib/splitclient-rb/engine/matchers/less_than_or_equal_to_semver_matcher.rb +28 -0
- data/lib/splitclient-rb/engine/matchers/matcher.rb +22 -0
- data/lib/splitclient-rb/engine/matchers/matches_string_matcher.rb +3 -2
- data/lib/splitclient-rb/engine/matchers/negation_matcher.rb +3 -2
- data/lib/splitclient-rb/engine/matchers/part_of_set_matcher.rb +2 -6
- data/lib/splitclient-rb/engine/matchers/prerequisites_matcher.rb +31 -0
- data/lib/splitclient-rb/engine/matchers/rule_based_segment_matcher.rb +78 -0
- data/lib/splitclient-rb/engine/matchers/semver.rb +201 -0
- data/lib/splitclient-rb/engine/matchers/set_matcher.rb +2 -1
- data/lib/splitclient-rb/engine/matchers/starts_with_matcher.rb +4 -3
- data/lib/splitclient-rb/engine/matchers/user_defined_segment_matcher.rb +3 -2
- data/lib/splitclient-rb/engine/matchers/whitelist_matcher.rb +7 -5
- data/lib/splitclient-rb/engine/metrics/binary_search_latency_tracker.rb +3 -65
- data/lib/splitclient-rb/engine/models/evaluation_options.rb +9 -0
- data/lib/splitclient-rb/engine/models/event_active_subscriptions.rb +14 -0
- data/lib/splitclient-rb/engine/models/events_metadata.rb +10 -0
- data/lib/splitclient-rb/engine/models/fallback_treatment.rb +11 -0
- data/lib/splitclient-rb/engine/models/fallback_treatments_configuration.rb +36 -0
- data/lib/splitclient-rb/engine/models/label.rb +3 -0
- data/lib/splitclient-rb/engine/models/sdk_event.rb +4 -0
- data/lib/splitclient-rb/engine/models/sdk_event_type.rb +4 -0
- data/lib/splitclient-rb/engine/models/sdk_internal_event.rb +8 -0
- data/lib/splitclient-rb/engine/models/sdk_internal_event_notification.rb +14 -0
- data/lib/splitclient-rb/engine/models/segment_type.rb +4 -0
- data/lib/splitclient-rb/engine/models/split_http_response.rb +19 -0
- data/lib/splitclient-rb/engine/models/valid_sdk_event.rb +14 -0
- data/lib/splitclient-rb/engine/parser/condition.rb +81 -20
- data/lib/splitclient-rb/engine/parser/evaluator.rb +40 -51
- data/lib/splitclient-rb/engine/push_manager.rb +66 -0
- data/lib/splitclient-rb/engine/status_manager.rb +39 -0
- data/lib/splitclient-rb/engine/sync_manager.rb +180 -0
- data/lib/splitclient-rb/engine/synchronizer.rb +231 -0
- data/lib/splitclient-rb/exceptions.rb +20 -1
- data/lib/splitclient-rb/helpers/decryption_helper.rb +25 -0
- data/lib/splitclient-rb/helpers/evaluator_helper.rb +37 -0
- data/lib/splitclient-rb/helpers/repository_helper.rb +61 -0
- data/lib/splitclient-rb/helpers/thread_helper.rb +24 -0
- data/lib/splitclient-rb/helpers/util.rb +26 -0
- data/lib/splitclient-rb/managers/split_manager.rb +58 -20
- data/lib/splitclient-rb/spec.rb +9 -0
- data/lib/splitclient-rb/split_config.rb +336 -54
- data/lib/splitclient-rb/split_factory.rb +219 -33
- data/lib/splitclient-rb/split_factory_builder.rb +1 -22
- data/lib/splitclient-rb/split_factory_registry.rb +63 -0
- data/lib/splitclient-rb/split_logger.rb +9 -10
- data/lib/splitclient-rb/sse/event_source/client.rb +263 -0
- data/lib/splitclient-rb/sse/event_source/event_parser.rb +65 -0
- data/lib/splitclient-rb/sse/event_source/event_types.rb +15 -0
- data/lib/splitclient-rb/sse/event_source/stream_data.rb +22 -0
- data/lib/splitclient-rb/sse/notification_manager_keeper.rb +84 -0
- data/lib/splitclient-rb/sse/notification_processor.rb +48 -0
- data/lib/splitclient-rb/sse/sse_handler.rb +44 -0
- data/lib/splitclient-rb/sse/workers/segments_worker.rb +62 -0
- data/lib/splitclient-rb/sse/workers/splits_worker.rb +149 -0
- data/lib/splitclient-rb/telemetry/domain/constants.rb +48 -0
- data/lib/splitclient-rb/telemetry/domain/structs.rb +35 -0
- data/lib/splitclient-rb/telemetry/evaluation_consumer.rb +14 -0
- data/lib/splitclient-rb/telemetry/evaluation_producer.rb +21 -0
- data/lib/splitclient-rb/telemetry/init_consumer.rb +14 -0
- data/lib/splitclient-rb/telemetry/init_producer.rb +19 -0
- data/lib/splitclient-rb/telemetry/memory/memory_evaluation_consumer.rb +32 -0
- data/lib/splitclient-rb/telemetry/memory/memory_evaluation_producer.rb +24 -0
- data/lib/splitclient-rb/telemetry/memory/memory_init_consumer.rb +28 -0
- data/lib/splitclient-rb/telemetry/memory/memory_init_producer.rb +34 -0
- data/lib/splitclient-rb/telemetry/memory/memory_runtime_consumer.rb +119 -0
- data/lib/splitclient-rb/telemetry/memory/memory_runtime_producer.rb +87 -0
- data/lib/splitclient-rb/telemetry/memory/memory_synchronizer.rb +213 -0
- data/lib/splitclient-rb/telemetry/redis/redis_evaluation_producer.rb +38 -0
- data/lib/splitclient-rb/telemetry/redis/redis_init_producer.rb +37 -0
- data/lib/splitclient-rb/telemetry/redis/redis_synchronizer.rb +27 -0
- data/lib/splitclient-rb/telemetry/runtime_consumer.rb +25 -0
- data/lib/splitclient-rb/telemetry/runtime_producer.rb +25 -0
- data/lib/splitclient-rb/telemetry/storages/memory.rb +159 -0
- data/lib/splitclient-rb/telemetry/sync_task.rb +36 -0
- data/lib/splitclient-rb/telemetry/synchronizer.rb +33 -0
- data/lib/splitclient-rb/utilitites.rb +8 -0
- data/lib/splitclient-rb/validators.rb +142 -38
- data/lib/splitclient-rb/version.rb +1 -1
- data/lib/splitclient-rb.rb +101 -16
- data/sonar-project.properties +6 -0
- data/splitclient-rb.gemspec +28 -23
- metadata +262 -82
- data/.travis.yml +0 -11
- data/Appraisals +0 -10
- data/Detailed-README.md +0 -588
- data/NEWS +0 -141
- data/lib/splitclient-rb/cache/repositories/metrics/memory_repository.rb +0 -127
- data/lib/splitclient-rb/cache/repositories/metrics/redis_repository.rb +0 -96
- data/lib/splitclient-rb/cache/repositories/metrics_repository.rb +0 -21
- data/lib/splitclient-rb/cache/senders/metrics_sender.rb +0 -56
- data/lib/splitclient-rb/cache/stores/sdk_blocker.rb +0 -46
- data/lib/splitclient-rb/cache/stores/segment_store.rb +0 -81
- data/lib/splitclient-rb/cache/stores/split_store.rb +0 -102
- data/lib/splitclient-rb/clients/localhost_split_client.rb +0 -183
- data/lib/splitclient-rb/engine/api/faraday_adapter/patched_net_http_persistent.rb +0 -46
- data/lib/splitclient-rb/engine/api/metrics.rb +0 -60
- data/lib/splitclient-rb/engine/metrics/metrics.rb +0 -80
- data/lib/splitclient-rb/engine/parser/split_adapter.rb +0 -81
- data/lib/splitclient-rb/localhost_split_factory.rb +0 -13
- data/lib/splitclient-rb/localhost_utils.rb +0 -59
- data/lib/splitclient-rb/managers/localhost_split_manager.rb +0 -60
|
@@ -1,183 +0,0 @@
|
|
|
1
|
-
module SplitIoClient
|
|
2
|
-
class LocalhostSplitClient
|
|
3
|
-
include SplitIoClient::LocalhostUtils
|
|
4
|
-
|
|
5
|
-
#
|
|
6
|
-
# variables to if the sdk is being used in localhost mode and store the list of features
|
|
7
|
-
attr_reader :localhost_mode
|
|
8
|
-
attr_reader :localhost_mode_features
|
|
9
|
-
|
|
10
|
-
#
|
|
11
|
-
# Creates a new split client instance that reads from the given splits file
|
|
12
|
-
#
|
|
13
|
-
# @param splits_file [File] file that contains some splits
|
|
14
|
-
#
|
|
15
|
-
# @return [LocalhostSplitIoClient] split.io localhost client instance
|
|
16
|
-
def initialize(splits_file, reload_rate = nil)
|
|
17
|
-
@localhost_mode = true
|
|
18
|
-
@localhost_mode_features = []
|
|
19
|
-
load_localhost_mode_features(splits_file, reload_rate)
|
|
20
|
-
end
|
|
21
|
-
|
|
22
|
-
#
|
|
23
|
-
# method that returns the sdk gem version
|
|
24
|
-
#
|
|
25
|
-
# @return [string] version value for this sdk
|
|
26
|
-
def self.sdk_version
|
|
27
|
-
'ruby-'+SplitIoClient::VERSION
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
#
|
|
31
|
-
# obtains the treatments and configs for a given set of features
|
|
32
|
-
#
|
|
33
|
-
# @param key [string] evaluation key, only used with yaml split files
|
|
34
|
-
# @param split_names [array] name of the features being validated
|
|
35
|
-
# @param attributes [hash] kept for consistency with actual SDK client. Omitted in calls
|
|
36
|
-
#
|
|
37
|
-
# @return [hash] map of treatments (split_name, treatment)
|
|
38
|
-
def get_treatments_with_config(key, split_names, attributes = nil)
|
|
39
|
-
get_localhost_treatments(key, split_names, attributes, 'get_treatments_with_config')
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
#
|
|
43
|
-
# obtains the treatments for a given set of features
|
|
44
|
-
#
|
|
45
|
-
# @param key [string] evaluation key, only used with yaml split files
|
|
46
|
-
# @param split_names [array] name of the features being validated
|
|
47
|
-
# @param attributes [hash] kept for consistency with actual SDK client. Omitted in calls
|
|
48
|
-
#
|
|
49
|
-
# @return [hash] map of treatments (split_name, treatment_name)
|
|
50
|
-
def get_treatments(key, split_names, attributes = nil)
|
|
51
|
-
treatments = get_localhost_treatments(key, split_names, attributes)
|
|
52
|
-
return treatments if treatments.nil?
|
|
53
|
-
keys = treatments.keys
|
|
54
|
-
treats = treatments.map { |_,t| t[:treatment] }
|
|
55
|
-
Hash[keys.zip(treats)]
|
|
56
|
-
end
|
|
57
|
-
|
|
58
|
-
#
|
|
59
|
-
# obtains the treatment for a given feature
|
|
60
|
-
#
|
|
61
|
-
# @param key [string] evaluation key, only used with yaml split files
|
|
62
|
-
# @param split_name [string] name of the feature that is being validated
|
|
63
|
-
# @param attributes [hash] kept for consistency with actual SDK client. Omitted in calls
|
|
64
|
-
#
|
|
65
|
-
# @return [string] corresponding treatment
|
|
66
|
-
def get_treatment(key, split_name, attributes = nil)
|
|
67
|
-
get_localhost_treatment(key, split_name, attributes)[:treatment]
|
|
68
|
-
end
|
|
69
|
-
|
|
70
|
-
#
|
|
71
|
-
# obtains the treatment and config for a given feature
|
|
72
|
-
#
|
|
73
|
-
# @param key [string] evaluation key, only used with yaml split files
|
|
74
|
-
# @param split_name [string] name of the feature that is being validated
|
|
75
|
-
# @param attributes [hash] kept for consistency with actual SDK client. Omitted in calls
|
|
76
|
-
#
|
|
77
|
-
# @return [hash] corresponding treatment and config
|
|
78
|
-
def get_treatment_with_config(key, split_name, attributes = nil)
|
|
79
|
-
get_localhost_treatment(key, split_name, attributes, 'get_treatment_with_config')
|
|
80
|
-
end
|
|
81
|
-
|
|
82
|
-
def track
|
|
83
|
-
end
|
|
84
|
-
|
|
85
|
-
private
|
|
86
|
-
|
|
87
|
-
#
|
|
88
|
-
# method to check if the sdk is running in localhost mode based on api key
|
|
89
|
-
#
|
|
90
|
-
# @return [boolean] True if is in localhost mode, false otherwise
|
|
91
|
-
def is_localhost_mode?
|
|
92
|
-
true
|
|
93
|
-
end
|
|
94
|
-
|
|
95
|
-
# @param key [string] evaluation key, only used with yaml split files
|
|
96
|
-
# @param split_name [string] name of the feature that is being validated
|
|
97
|
-
#
|
|
98
|
-
# @return [Hash] corresponding treatment and config, control otherwise
|
|
99
|
-
def get_localhost_treatment(key, split_name, attributes, calling_method = 'get_treatment')
|
|
100
|
-
control_treatment = { label: Engine::Models::Label::EXCEPTION, treatment: SplitIoClient::Engine::Models::Treatment::CONTROL, config: nil }
|
|
101
|
-
parsed_control_treatment = parsed_treatment(control_treatment)
|
|
102
|
-
|
|
103
|
-
bucketing_key, matching_key = keys_from_key(key)
|
|
104
|
-
return parsed_control_treatment unless SplitIoClient::Validators.valid_get_treatment_parameters(calling_method, key, split_name, matching_key, bucketing_key, attributes)
|
|
105
|
-
|
|
106
|
-
sanitized_split_name = split_name.to_s.strip
|
|
107
|
-
|
|
108
|
-
if split_name.to_s != sanitized_split_name
|
|
109
|
-
SplitIoClient.configuration.logger.warn("get_treatment: split_name #{split_name} has extra whitespace, trimming")
|
|
110
|
-
split_name = sanitized_split_name
|
|
111
|
-
end
|
|
112
|
-
|
|
113
|
-
treatment = @localhost_mode_features.select { |h| h[:feature] == split_name && has_key(h[:keys], key) }.last
|
|
114
|
-
|
|
115
|
-
if treatment.nil?
|
|
116
|
-
treatment = @localhost_mode_features.select { |h| h[:feature] == split_name && h[:keys] == nil }.last
|
|
117
|
-
end
|
|
118
|
-
|
|
119
|
-
if treatment && treatment[:treatment]
|
|
120
|
-
{
|
|
121
|
-
treatment: treatment[:treatment],
|
|
122
|
-
config: treatment[:config]
|
|
123
|
-
}
|
|
124
|
-
else
|
|
125
|
-
parsed_control_treatment
|
|
126
|
-
end
|
|
127
|
-
end
|
|
128
|
-
|
|
129
|
-
def get_localhost_treatments(key, split_names, attributes = nil, calling_method = 'get_treatments')
|
|
130
|
-
return nil unless SplitIoClient::Validators.valid_get_treatments_parameters(calling_method, split_names)
|
|
131
|
-
|
|
132
|
-
sanitized_split_names = sanitize_split_names(calling_method, split_names)
|
|
133
|
-
|
|
134
|
-
if sanitized_split_names.empty?
|
|
135
|
-
SplitIoClient.configuration.logger.error("#{calling_method}: split_names must be a non-empty Array")
|
|
136
|
-
return {}
|
|
137
|
-
end
|
|
138
|
-
|
|
139
|
-
split_names.each_with_object({}) do |split_name, memo|
|
|
140
|
-
memo.merge!(split_name => get_treatment_with_config(key, split_name, attributes))
|
|
141
|
-
end
|
|
142
|
-
end
|
|
143
|
-
|
|
144
|
-
def sanitize_split_names(calling_method, split_names)
|
|
145
|
-
split_names.compact.uniq.select do |split_name|
|
|
146
|
-
if (split_name.is_a?(String) || split_name.is_a?(Symbol)) && !split_name.empty?
|
|
147
|
-
true
|
|
148
|
-
elsif split_name.is_a?(String) && split_name.empty?
|
|
149
|
-
SplitIoClient.configuration.logger.warn("#{calling_method}: you passed an empty split_name, split_name must be a non-empty String or a Symbol")
|
|
150
|
-
false
|
|
151
|
-
else
|
|
152
|
-
SplitIoClient.configuration.logger.warn("#{calling_method}: you passed an invalid split_name, split_name must be a non-empty String or a Symbol")
|
|
153
|
-
false
|
|
154
|
-
end
|
|
155
|
-
end
|
|
156
|
-
end
|
|
157
|
-
|
|
158
|
-
def parsed_treatment(treatment_data)
|
|
159
|
-
{
|
|
160
|
-
treatment: treatment_data[:treatment],
|
|
161
|
-
config: treatment_data[:config]
|
|
162
|
-
}
|
|
163
|
-
end
|
|
164
|
-
|
|
165
|
-
def has_key(keys, key)
|
|
166
|
-
case keys
|
|
167
|
-
when Array then keys.include? key
|
|
168
|
-
when String then keys == key
|
|
169
|
-
else
|
|
170
|
-
false
|
|
171
|
-
end
|
|
172
|
-
end
|
|
173
|
-
|
|
174
|
-
def keys_from_key(key)
|
|
175
|
-
case key
|
|
176
|
-
when Hash
|
|
177
|
-
key.values_at(:bucketing_key, :matching_key).map { |k| k.nil? ? nil : k }
|
|
178
|
-
else
|
|
179
|
-
[nil, key].map { |k| k.nil? ? nil : k }
|
|
180
|
-
end
|
|
181
|
-
end
|
|
182
|
-
end
|
|
183
|
-
end
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module SplitIoClient
|
|
4
|
-
module FaradayAdapter
|
|
5
|
-
class PatchedNetHttpPersistent < Faraday::Adapter::NetHttpPersistent
|
|
6
|
-
##
|
|
7
|
-
# Borrowed directly from the latest `NetHttpPersistent` adapter implementation.
|
|
8
|
-
#
|
|
9
|
-
# https://github.com/lostisland/faraday/blob/master/lib/faraday/adapter/net_http_persistent.rb
|
|
10
|
-
#
|
|
11
|
-
def net_http_connection(env)
|
|
12
|
-
@cached_connection ||=
|
|
13
|
-
if Net::HTTP::Persistent.instance_method(:initialize).parameters.first == [:key, :name]
|
|
14
|
-
Net::HTTP::Persistent.new(name: 'Faraday')
|
|
15
|
-
else
|
|
16
|
-
Net::HTTP::Persistent.new('Faraday')
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
proxy_uri = proxy_uri(env)
|
|
20
|
-
@cached_connection.proxy = proxy_uri if @cached_connection.proxy_uri != proxy_uri
|
|
21
|
-
@cached_connection
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
def proxy_uri(env)
|
|
25
|
-
proxy_uri = nil
|
|
26
|
-
if (proxy = env[:request][:proxy])
|
|
27
|
-
proxy_uri = ::URI::HTTP === proxy[:uri] ? proxy[:uri].dup : ::URI.parse(proxy[:uri].to_s)
|
|
28
|
-
proxy_uri.user = proxy_uri.password = nil
|
|
29
|
-
# awful patch for net-http-persistent 2.8 not unescaping user/password
|
|
30
|
-
(
|
|
31
|
-
class << proxy_uri;
|
|
32
|
-
self;
|
|
33
|
-
end).class_eval do
|
|
34
|
-
define_method(:user) { proxy[:user] }
|
|
35
|
-
define_method(:password) { proxy[:password] }
|
|
36
|
-
end if proxy[:user]
|
|
37
|
-
end
|
|
38
|
-
proxy_uri
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
def with_net_http_connection(env)
|
|
42
|
-
yield net_http_connection(env)
|
|
43
|
-
end
|
|
44
|
-
end
|
|
45
|
-
end
|
|
46
|
-
end
|
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module SplitIoClient
|
|
4
|
-
module Api
|
|
5
|
-
class Metrics < Client
|
|
6
|
-
def initialize(api_key, metrics_repository)
|
|
7
|
-
@api_key = api_key
|
|
8
|
-
@metrics_repository = metrics_repository
|
|
9
|
-
end
|
|
10
|
-
|
|
11
|
-
def post
|
|
12
|
-
post_latencies
|
|
13
|
-
post_counts
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
private
|
|
17
|
-
|
|
18
|
-
def post_latencies
|
|
19
|
-
if @metrics_repository.latencies.empty?
|
|
20
|
-
SplitLogger.log_if_debug('No latencies to report.')
|
|
21
|
-
else
|
|
22
|
-
@metrics_repository.latencies.each do |name, latencies|
|
|
23
|
-
metrics_time = { name: name, latencies: latencies }
|
|
24
|
-
|
|
25
|
-
response = post_api("#{SplitIoClient.configuration.events_uri}/metrics/time", @api_key, metrics_time)
|
|
26
|
-
|
|
27
|
-
log_status(response, metrics_time.size)
|
|
28
|
-
end
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
@metrics_repository.clear_latencies
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
def post_counts
|
|
35
|
-
if @metrics_repository.counts.empty?
|
|
36
|
-
SplitLogger.log_if_debug('No counts to report.')
|
|
37
|
-
else
|
|
38
|
-
@metrics_repository.counts.each do |name, count|
|
|
39
|
-
metrics_count = { name: name, delta: count }
|
|
40
|
-
|
|
41
|
-
response = post_api("#{SplitIoClient.configuration.events_uri}/metrics/counter", @api_key, metrics_count)
|
|
42
|
-
|
|
43
|
-
log_status(response, metrics_count.size)
|
|
44
|
-
end
|
|
45
|
-
end
|
|
46
|
-
@metrics_repository.clear_counts
|
|
47
|
-
end
|
|
48
|
-
|
|
49
|
-
def log_status(response, info_to_log)
|
|
50
|
-
if response.success?
|
|
51
|
-
SplitLogger.log_if_debug("Metric time reported: #{info_to_log}")
|
|
52
|
-
else
|
|
53
|
-
SplitLogger.log_error("Unexpected status code while posting time metrics: #{response.status}" \
|
|
54
|
-
' - Check your API key and base URI')
|
|
55
|
-
raise 'Split SDK failed to connect to backend to post metrics'
|
|
56
|
-
end
|
|
57
|
-
end
|
|
58
|
-
end
|
|
59
|
-
end
|
|
60
|
-
end
|
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
module SplitIoClient
|
|
2
|
-
|
|
3
|
-
#
|
|
4
|
-
# class to handle cached metrics
|
|
5
|
-
#
|
|
6
|
-
class Metrics < NoMethodError
|
|
7
|
-
|
|
8
|
-
@counter
|
|
9
|
-
@delta
|
|
10
|
-
|
|
11
|
-
#
|
|
12
|
-
# cached latencies
|
|
13
|
-
#
|
|
14
|
-
# @return [object] array of latencies
|
|
15
|
-
attr_accessor :latencies
|
|
16
|
-
|
|
17
|
-
#
|
|
18
|
-
# cached counts
|
|
19
|
-
#
|
|
20
|
-
# @return [object] array of counts
|
|
21
|
-
attr_accessor :counts
|
|
22
|
-
|
|
23
|
-
#
|
|
24
|
-
# cached gauges
|
|
25
|
-
#
|
|
26
|
-
# @return [object] array of gauges
|
|
27
|
-
attr_accessor :gauges
|
|
28
|
-
|
|
29
|
-
#
|
|
30
|
-
# quese size for cached arrays
|
|
31
|
-
#
|
|
32
|
-
# @return [int] queue size
|
|
33
|
-
attr_accessor :queue_size
|
|
34
|
-
|
|
35
|
-
def initialize(queue_size, repository)
|
|
36
|
-
@queue_size = queue_size
|
|
37
|
-
@binary_search = SplitIoClient::BinarySearchLatencyTracker.new
|
|
38
|
-
@repository = repository
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
#
|
|
42
|
-
# creates a new entry in the array for cached counts
|
|
43
|
-
#
|
|
44
|
-
# @param counter [string] name of the counter
|
|
45
|
-
# @delta [int] value of the counter
|
|
46
|
-
#
|
|
47
|
-
# @return void
|
|
48
|
-
def count(counter, delta)
|
|
49
|
-
return if (delta <= 0) || counter.nil? || counter.strip.empty?
|
|
50
|
-
|
|
51
|
-
@repository.add_count(counter, delta)
|
|
52
|
-
end
|
|
53
|
-
|
|
54
|
-
#
|
|
55
|
-
# creates a new entry in the array for cached time metrics
|
|
56
|
-
#
|
|
57
|
-
# @param operation [string] name of the operation
|
|
58
|
-
# @time_in_ms [number] time in miliseconds
|
|
59
|
-
#
|
|
60
|
-
# @return void
|
|
61
|
-
def time(operation, time_in_ms)
|
|
62
|
-
return if operation.nil? || operation.empty? || time_in_ms < 0
|
|
63
|
-
|
|
64
|
-
@repository.add_latency(operation, time_in_ms, @binary_search)
|
|
65
|
-
end
|
|
66
|
-
|
|
67
|
-
#
|
|
68
|
-
# creates a new entry in the array for cached gauges
|
|
69
|
-
#
|
|
70
|
-
# @param gauge [string] name of the gauge
|
|
71
|
-
# @value [number] value of the gauge
|
|
72
|
-
#
|
|
73
|
-
# @return void
|
|
74
|
-
def gauge(gauge, value)
|
|
75
|
-
return if gauge.nil? || gauge.empty?
|
|
76
|
-
|
|
77
|
-
@repository.add_gauge(gauge, value)
|
|
78
|
-
end
|
|
79
|
-
end
|
|
80
|
-
end
|
|
@@ -1,81 +0,0 @@
|
|
|
1
|
-
require 'json'
|
|
2
|
-
require 'thread'
|
|
3
|
-
|
|
4
|
-
include SplitIoClient::Cache::Stores
|
|
5
|
-
include SplitIoClient::Cache::Senders
|
|
6
|
-
|
|
7
|
-
module SplitIoClient
|
|
8
|
-
#
|
|
9
|
-
# acts as an api adapater to connect to split endpoints
|
|
10
|
-
# uses a configuration object that can be modified when creating the client instance
|
|
11
|
-
# also, uses safe threads to execute fetches and post give the time execution values from the config
|
|
12
|
-
#
|
|
13
|
-
class SplitAdapter < NoMethodError
|
|
14
|
-
attr_reader :splits_repository, :segments_repository, :impressions_repository, :metrics
|
|
15
|
-
|
|
16
|
-
#
|
|
17
|
-
# Creates a new split api adapter instance that consumes split api endpoints
|
|
18
|
-
#
|
|
19
|
-
# @param api_key [String] the API key for your split account
|
|
20
|
-
# @param splits_repository [SplitsRepository] SplitsRepository instance to store splits in
|
|
21
|
-
# @param segments_repository [SegmentsRepository] SegmentsRepository instance to store segments in
|
|
22
|
-
# @param impressions_repository [ImpressionsRepository] ImpressionsRepository instance to store impressions in
|
|
23
|
-
# @param metrics_repository [MetricsRepository] MetricsRepository instance to store metrics in
|
|
24
|
-
# @param sdk_blocker [SDKBlocker] SDKBlocker instance which blocks splits_repository/segments_repository
|
|
25
|
-
#
|
|
26
|
-
# @return [SplitIoClient] split.io client instance
|
|
27
|
-
def initialize(
|
|
28
|
-
api_key,
|
|
29
|
-
splits_repository,
|
|
30
|
-
segments_repository,
|
|
31
|
-
impressions_repository,
|
|
32
|
-
metrics_repository,
|
|
33
|
-
events_repository,
|
|
34
|
-
sdk_blocker
|
|
35
|
-
)
|
|
36
|
-
@api_key = api_key
|
|
37
|
-
@splits_repository = splits_repository
|
|
38
|
-
@segments_repository = segments_repository
|
|
39
|
-
@impressions_repository = impressions_repository
|
|
40
|
-
@metrics_repository = metrics_repository
|
|
41
|
-
@events_repository = events_repository
|
|
42
|
-
@metrics = Metrics.new(100, @metrics_repository)
|
|
43
|
-
@sdk_blocker = sdk_blocker
|
|
44
|
-
|
|
45
|
-
start_standalone_components if SplitIoClient.configuration.mode == :standalone
|
|
46
|
-
end
|
|
47
|
-
|
|
48
|
-
def start_standalone_components
|
|
49
|
-
split_store
|
|
50
|
-
segment_store
|
|
51
|
-
metrics_sender
|
|
52
|
-
impressions_sender
|
|
53
|
-
events_sender
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
# Starts thread which loops constantly and stores splits in the splits_repository of choice
|
|
57
|
-
def split_store
|
|
58
|
-
SplitStore.new(@splits_repository, @api_key, @metrics, @sdk_blocker).call
|
|
59
|
-
end
|
|
60
|
-
|
|
61
|
-
# Starts thread which loops constantly and stores segments in the segments_repository of choice
|
|
62
|
-
def segment_store
|
|
63
|
-
SegmentStore.new(@segments_repository, @api_key, @metrics, @sdk_blocker).call
|
|
64
|
-
end
|
|
65
|
-
|
|
66
|
-
# Starts thread which loops constantly and sends impressions to the Split API
|
|
67
|
-
def impressions_sender
|
|
68
|
-
ImpressionsSender.new(@impressions_repository, @api_key).call
|
|
69
|
-
end
|
|
70
|
-
|
|
71
|
-
# Starts thread which loops constantly and sends metrics to the Split API
|
|
72
|
-
def metrics_sender
|
|
73
|
-
MetricsSender.new(@metrics_repository, @api_key).call
|
|
74
|
-
end
|
|
75
|
-
|
|
76
|
-
# Starts thread which loops constantly and sends events to the Split API
|
|
77
|
-
def events_sender
|
|
78
|
-
EventsSender.new(@events_repository, @api_key).call
|
|
79
|
-
end
|
|
80
|
-
end
|
|
81
|
-
end
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
module SplitIoClient
|
|
2
|
-
class LocalhostSplitFactory
|
|
3
|
-
attr_reader :client, :manager
|
|
4
|
-
|
|
5
|
-
def initialize(splits_file, reload_rate = nil, logger = nil)
|
|
6
|
-
@splits_file = splits_file
|
|
7
|
-
@reload_rate = reload_rate
|
|
8
|
-
|
|
9
|
-
@client = LocalhostSplitClient.new(@splits_file, @reload_rate)
|
|
10
|
-
@manager = LocalhostSplitManager.new(@splits_file, @reload_rate)
|
|
11
|
-
end
|
|
12
|
-
end
|
|
13
|
-
end
|
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
module SplitIoClient
|
|
2
|
-
module LocalhostUtils
|
|
3
|
-
|
|
4
|
-
require 'yaml'
|
|
5
|
-
#
|
|
6
|
-
# method to set localhost mode features by reading the given .splits
|
|
7
|
-
#
|
|
8
|
-
# @param splits_file [File] the .split file that contains the splits
|
|
9
|
-
# @param reload_rate [Integer] the number of seconds to reload splits_file
|
|
10
|
-
# @return nil
|
|
11
|
-
def load_localhost_mode_features(splits_file, reload_rate = nil)
|
|
12
|
-
return @localhost_mode_features unless File.exists?(splits_file)
|
|
13
|
-
|
|
14
|
-
store_features(splits_file)
|
|
15
|
-
|
|
16
|
-
return unless reload_rate
|
|
17
|
-
|
|
18
|
-
Thread.new do
|
|
19
|
-
loop do
|
|
20
|
-
@localhost_mode_features = []
|
|
21
|
-
store_features(splits_file)
|
|
22
|
-
|
|
23
|
-
sleep(SplitIoClient::Utilities.randomize_interval(reload_rate))
|
|
24
|
-
end
|
|
25
|
-
end
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
def store_features(splits_file)
|
|
29
|
-
yaml_extensions = [".yml", ".yaml"]
|
|
30
|
-
if yaml_extensions.include? File.extname(splits_file)
|
|
31
|
-
store_yaml_features(splits_file)
|
|
32
|
-
else
|
|
33
|
-
store_plain_text_features(splits_file)
|
|
34
|
-
end
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
private
|
|
38
|
-
|
|
39
|
-
def store_plain_text_features(splits_file)
|
|
40
|
-
File.open(splits_file).each do |line|
|
|
41
|
-
feature, treatment = line.strip.split(' ')
|
|
42
|
-
|
|
43
|
-
next if line.start_with?('#') || line.strip.empty?
|
|
44
|
-
|
|
45
|
-
@localhost_mode_features << { feature: feature, treatment: treatment, key: nil, config: nil }
|
|
46
|
-
end
|
|
47
|
-
end
|
|
48
|
-
|
|
49
|
-
def store_yaml_features(splits_file)
|
|
50
|
-
YAML.load(File.read(splits_file)).each do |feature|
|
|
51
|
-
feat_symbolized_keys = feature[feature.keys.first].inject({}){|memo,(k,v)| memo[k.to_sym] = v; memo}
|
|
52
|
-
|
|
53
|
-
feat_symbolized_keys[:config] = feat_symbolized_keys[:config].to_json
|
|
54
|
-
|
|
55
|
-
@localhost_mode_features << { feature: feature.keys.first }.merge(feat_symbolized_keys)
|
|
56
|
-
end
|
|
57
|
-
end
|
|
58
|
-
end
|
|
59
|
-
end
|
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
module SplitIoClient
|
|
2
|
-
class LocalhostSplitManager
|
|
3
|
-
include SplitIoClient::LocalhostUtils
|
|
4
|
-
|
|
5
|
-
#
|
|
6
|
-
# Creates a new split manager instance that holds the splits from a given file
|
|
7
|
-
#
|
|
8
|
-
# @param splits_file [File] the .split file that contains the splits
|
|
9
|
-
# @param reload_rate [Integer] the number of seconds to reload splits_file
|
|
10
|
-
#
|
|
11
|
-
# @return [LocalhostSplitIoManager] split.io localhost manager instance
|
|
12
|
-
def initialize(splits_file, reload_rate = nil)
|
|
13
|
-
@localhost_mode = true
|
|
14
|
-
@localhost_mode_features = []
|
|
15
|
-
|
|
16
|
-
load_localhost_mode_features(splits_file, reload_rate)
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
#
|
|
20
|
-
# method to get a split view
|
|
21
|
-
#
|
|
22
|
-
# @returns a split view
|
|
23
|
-
def split(split_name)
|
|
24
|
-
features = @localhost_mode_features.find_all { |feat| feat[:feature] == split_name }
|
|
25
|
-
|
|
26
|
-
return nil if features.nil?
|
|
27
|
-
|
|
28
|
-
treatments = features.map { |feat| feat[:treatment] }
|
|
29
|
-
|
|
30
|
-
configs = Hash[ features.map { |feat| [ feat[:treatment].to_sym, feat[:config] ] } ]
|
|
31
|
-
|
|
32
|
-
{
|
|
33
|
-
change_number: nil,
|
|
34
|
-
killed: false,
|
|
35
|
-
name: split_name,
|
|
36
|
-
traffic_type: nil,
|
|
37
|
-
treatments: treatments,
|
|
38
|
-
configs: configs
|
|
39
|
-
}
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
#
|
|
43
|
-
# method to get the split list from the client
|
|
44
|
-
#
|
|
45
|
-
# @returns Array of split view
|
|
46
|
-
def splits
|
|
47
|
-
split_names.map do |split_name|
|
|
48
|
-
split(split_name)
|
|
49
|
-
end
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
#
|
|
53
|
-
# method to get the list of just split names. Ideal for ietrating and calling client.get_treatment
|
|
54
|
-
#
|
|
55
|
-
# @returns [object] array of split names (String)
|
|
56
|
-
def split_names
|
|
57
|
-
@localhost_mode_features.map{ |feat| feat[:feature]}.uniq
|
|
58
|
-
end
|
|
59
|
-
end
|
|
60
|
-
end
|