splitclient-rb 8.10.1.pre.rc.2-java → 8.11.0-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/CHANGES.txt +8 -2
- data/LICENSE +1 -1
- data/NOTICE.txt +5 -0
- data/lib/splitclient-rb/cache/repositories/rule_based_segments_repository.rb +14 -1
- data/lib/splitclient-rb/cache/repositories/segments_repository.rb +13 -2
- data/lib/splitclient-rb/cache/repositories/splits_repository.rb +23 -1
- data/lib/splitclient-rb/clients/split_client.rb +12 -3
- data/lib/splitclient-rb/engine/api/faraday_middleware/gzip.rb +1 -0
- data/lib/splitclient-rb/engine/api/splits.rb +2 -2
- data/lib/splitclient-rb/engine/auth_api_client.rb +7 -3
- 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/models/event_active_subscriptions.rb +14 -0
- data/lib/splitclient-rb/engine/models/events_metadata.rb +10 -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 +16 -0
- data/lib/splitclient-rb/engine/models/valid_sdk_event.rb +14 -0
- data/lib/splitclient-rb/engine/status_manager.rb +7 -1
- data/lib/splitclient-rb/engine/sync_manager.rb +10 -6
- data/lib/splitclient-rb/split_factory.rb +20 -5
- data/lib/splitclient-rb/sse/event_source/client.rb +14 -15
- data/lib/splitclient-rb/sse/event_source/event_parser.rb +2 -2
- data/lib/splitclient-rb/sse/notification_manager_keeper.rb +3 -3
- data/lib/splitclient-rb/sse/workers/segments_worker.rb +4 -4
- data/lib/splitclient-rb/sse/workers/splits_worker.rb +9 -5
- data/lib/splitclient-rb/version.rb +1 -1
- data/lib/splitclient-rb.rb +12 -0
- metadata +15 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: dd598b2e9efb5540f5fb04f365b8f39cca8ded197ba8ff182a4335993f7e6d6e
|
|
4
|
+
data.tar.gz: '09b81db07f63a50e86450914abe2301bef42decfda218f8bce9a9077333040ba'
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 26ef8859967e564baf87ac4b045eb49eb2001faea6bc38e331a61c9df8d9ff03ad8f06dd226b677e85dc3e5d3c9b6b951b1f1f6abdc4f01f8b0d44bd8ace7f8c
|
|
7
|
+
data.tar.gz: baeef34eda98aefd67bd494e60f6fe7e866ea43cb17f1fa299b49800373d65e17611b979dd2fc60bd169f3c4659c6aebbc6e2dbe47c374002239e4c13111970e
|
data/CHANGES.txt
CHANGED
|
@@ -1,7 +1,13 @@
|
|
|
1
1
|
CHANGES
|
|
2
2
|
|
|
3
|
-
8.
|
|
4
|
-
-
|
|
3
|
+
8.11.0 (Mar, 12, 2026)
|
|
4
|
+
- Added the ability to listen to different events triggered by the SDK. Read more in our docs.
|
|
5
|
+
- SDK_UPDATE notify when a flag or user segment has changed
|
|
6
|
+
- SDK_READY notify when the SDK is ready to evaluate
|
|
7
|
+
|
|
8
|
+
8.10.1 (Jan 28, 2025)
|
|
9
|
+
- Fixed rule-based segment matcher to exit when a conition is met.
|
|
10
|
+
- Fixed impressions properties format in redis mode.
|
|
5
11
|
|
|
6
12
|
8.10.0 (Nov 28, 2025)
|
|
7
13
|
- Updated socketry gem used in streaming feature with built-in socket lib.
|
data/LICENSE
CHANGED
|
@@ -157,7 +157,7 @@ Apache License
|
|
|
157
157
|
file or class name and description of purpose be included on the
|
|
158
158
|
same "printed page" as the copyright notice for easier
|
|
159
159
|
identification within third-party archives.
|
|
160
|
-
Copyright
|
|
160
|
+
Copyright 2025 Harness Corporation
|
|
161
161
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
162
162
|
you may not use this file except in compliance with the License.
|
|
163
163
|
You may obtain a copy of the License at
|
data/NOTICE.txt
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
Harness Feature Management JavaScript SDK Copyright 2024-2026 Harness Inc.
|
|
2
|
+
|
|
3
|
+
This product includes software developed at Harness Inc. (https://harness.io/).
|
|
4
|
+
|
|
5
|
+
This product includes software originally developed by Split Software, Inc. (https://www.split.io/). Copyright 2016-2024 Split Software, Inc.
|
|
@@ -28,7 +28,7 @@ module SplitIoClient
|
|
|
28
28
|
RB_SEGMENTS_PREFIX = '.rbsegment.'
|
|
29
29
|
REGISTERED_PREFIX = '.segments.registered'
|
|
30
30
|
|
|
31
|
-
def initialize(config)
|
|
31
|
+
def initialize(config, internal_events_queue)
|
|
32
32
|
super(config)
|
|
33
33
|
@adapter = case @config.cache_adapter.class.to_s
|
|
34
34
|
when 'SplitIoClient::Cache::Adapters::RedisAdapter'
|
|
@@ -40,12 +40,25 @@ module SplitIoClient
|
|
|
40
40
|
@adapter.set_string(namespace_key(TILL_PREFIX), '-1')
|
|
41
41
|
@adapter.initialize_map(namespace_key(REGISTERED_PREFIX))
|
|
42
42
|
end
|
|
43
|
+
@internal_events_queue = internal_events_queue
|
|
43
44
|
end
|
|
44
45
|
|
|
45
46
|
def update(to_add, to_delete, new_change_number)
|
|
46
47
|
to_add.each{ |rule_based_segment| add_rule_based_segment(rule_based_segment) }
|
|
47
48
|
to_delete.each{ |rule_based_segment| remove_rule_based_segment(rule_based_segment) }
|
|
48
49
|
set_change_number(new_change_number)
|
|
50
|
+
|
|
51
|
+
if to_add.length > 0 || to_delete.length > 0
|
|
52
|
+
@internal_events_queue.push(
|
|
53
|
+
SplitIoClient::Engine::Models::SdkInternalEventNotification.new(
|
|
54
|
+
SplitIoClient::Engine::Models::SdkInternalEvent::RB_SEGMENTS_UPDATED,
|
|
55
|
+
SplitIoClient::Engine::Models::EventsMetadata.new(
|
|
56
|
+
SplitIoClient::Engine::Models::SdkEventType::SEGMENTS_UPDATE,
|
|
57
|
+
[]
|
|
58
|
+
)
|
|
59
|
+
)
|
|
60
|
+
)
|
|
61
|
+
end
|
|
49
62
|
end
|
|
50
63
|
|
|
51
64
|
def get_rule_based_segment(name)
|
|
@@ -6,7 +6,7 @@ module SplitIoClient
|
|
|
6
6
|
|
|
7
7
|
attr_reader :adapter
|
|
8
8
|
|
|
9
|
-
def initialize(config)
|
|
9
|
+
def initialize(config, internal_events_queue)
|
|
10
10
|
super(config)
|
|
11
11
|
@adapter = case @config.cache_adapter.class.to_s
|
|
12
12
|
when 'SplitIoClient::Cache::Adapters::RedisAdapter'
|
|
@@ -15,6 +15,7 @@ module SplitIoClient
|
|
|
15
15
|
@config.cache_adapter
|
|
16
16
|
end
|
|
17
17
|
@adapter.set_bool(namespace_key('.ready'), false) unless @config.mode.equal?(:consumer)
|
|
18
|
+
@internal_events_queue = internal_events_queue
|
|
18
19
|
end
|
|
19
20
|
|
|
20
21
|
# Receives segment data, adds and removes segements from the store
|
|
@@ -22,9 +23,19 @@ module SplitIoClient
|
|
|
22
23
|
name = segment[:name]
|
|
23
24
|
|
|
24
25
|
@adapter.initialize_set(segment_data(name)) unless @adapter.exists?(segment_data(name))
|
|
25
|
-
|
|
26
26
|
add_keys(name, segment[:added])
|
|
27
27
|
remove_keys(name, segment[:removed])
|
|
28
|
+
if segment[:added].length > 0 || segment[:removed].length > 0
|
|
29
|
+
@internal_events_queue.push(
|
|
30
|
+
SplitIoClient::Engine::Models::SdkInternalEventNotification.new(
|
|
31
|
+
SplitIoClient::Engine::Models::SdkInternalEvent::SEGMENTS_UPDATED,
|
|
32
|
+
SplitIoClient::Engine::Models::EventsMetadata.new(
|
|
33
|
+
SplitIoClient::Engine::Models::SdkEventType::SEGMENTS_UPDATE,
|
|
34
|
+
[]
|
|
35
|
+
)
|
|
36
|
+
)
|
|
37
|
+
)
|
|
38
|
+
end
|
|
28
39
|
end
|
|
29
40
|
|
|
30
41
|
def get_segment_keys(name)
|
|
@@ -35,7 +35,7 @@ module SplitIoClient
|
|
|
35
35
|
SPLIT_PREFIX = '.split.'
|
|
36
36
|
READY_PREFIX = '.splits.ready'
|
|
37
37
|
|
|
38
|
-
def initialize(config, flag_sets_repository, flag_set_filter)
|
|
38
|
+
def initialize(config, flag_sets_repository, flag_set_filter, internal_events_queue)
|
|
39
39
|
super(config)
|
|
40
40
|
@tt_cache = {}
|
|
41
41
|
@adapter = case @config.cache_adapter.class.to_s
|
|
@@ -46,6 +46,7 @@ module SplitIoClient
|
|
|
46
46
|
end
|
|
47
47
|
@flag_sets = flag_sets_repository
|
|
48
48
|
@flag_set_filter = flag_set_filter
|
|
49
|
+
@internal_events_queue = internal_events_queue
|
|
49
50
|
initialize_keys
|
|
50
51
|
end
|
|
51
52
|
|
|
@@ -53,6 +54,18 @@ module SplitIoClient
|
|
|
53
54
|
to_add.each{ |feature_flag| add_feature_flag(feature_flag) }
|
|
54
55
|
to_delete.each{ |feature_flag| remove_feature_flag(feature_flag) }
|
|
55
56
|
set_change_number(new_change_number)
|
|
57
|
+
|
|
58
|
+
if to_add.length > 0 || to_delete.length > 0
|
|
59
|
+
@internal_events_queue.push(
|
|
60
|
+
SplitIoClient::Engine::Models::SdkInternalEventNotification.new(
|
|
61
|
+
SplitIoClient::Engine::Models::SdkInternalEvent::FLAGS_UPDATED,
|
|
62
|
+
SplitIoClient::Engine::Models::EventsMetadata.new(
|
|
63
|
+
SplitIoClient::Engine::Models::SdkEventType::FLAG_UPDATE,
|
|
64
|
+
to_add.map {|flag| flag[:name]} | to_delete.map {|flag| flag[:name]}
|
|
65
|
+
)
|
|
66
|
+
)
|
|
67
|
+
)
|
|
68
|
+
end
|
|
56
69
|
end
|
|
57
70
|
|
|
58
71
|
def get_split(name)
|
|
@@ -140,6 +153,15 @@ module SplitIoClient
|
|
|
140
153
|
split[:changeNumber] = change_number
|
|
141
154
|
|
|
142
155
|
@adapter.set_string(namespace_key(".split.#{split_name}"), split.to_json)
|
|
156
|
+
@internal_events_queue.push(
|
|
157
|
+
SplitIoClient::Engine::Models::SdkInternalEventNotification.new(
|
|
158
|
+
SplitIoClient::Engine::Models::SdkInternalEvent::FLAG_KILLED_NOTIFICATION,
|
|
159
|
+
SplitIoClient::Engine::Models::EventsMetadata.new(
|
|
160
|
+
SplitIoClient::Engine::Models::SdkEventType::FLAG_UPDATE,
|
|
161
|
+
[split_name]
|
|
162
|
+
)
|
|
163
|
+
)
|
|
164
|
+
)
|
|
143
165
|
end
|
|
144
166
|
|
|
145
167
|
def splits_count
|
|
@@ -18,7 +18,7 @@ module SplitIoClient
|
|
|
18
18
|
# @param sdk_key [String] the SDK key for your split account
|
|
19
19
|
#
|
|
20
20
|
# @return [SplitIoClient] split.io client instance
|
|
21
|
-
def initialize(sdk_key, repositories, status_manager, config, impressions_manager, telemetry_evaluation_producer, evaluator, split_validator, fallback_treatment_calculator)
|
|
21
|
+
def initialize(sdk_key, repositories, status_manager, config, impressions_manager, telemetry_evaluation_producer, evaluator, split_validator, fallback_treatment_calculator, events_manager)
|
|
22
22
|
@api_key = sdk_key
|
|
23
23
|
@splits_repository = repositories[:splits]
|
|
24
24
|
@segments_repository = repositories[:segments]
|
|
@@ -33,6 +33,7 @@ module SplitIoClient
|
|
|
33
33
|
@split_validator = split_validator
|
|
34
34
|
@evaluator = evaluator
|
|
35
35
|
@fallback_treatment_calculator = fallback_treatment_calculator
|
|
36
|
+
@events_manager = events_manager
|
|
36
37
|
end
|
|
37
38
|
|
|
38
39
|
def get_treatment(
|
|
@@ -117,11 +118,11 @@ module SplitIoClient
|
|
|
117
118
|
@config.logger.info('Split client shutdown started...') if @config.debug_enabled
|
|
118
119
|
if !@config.cache_adapter.is_a?(SplitIoClient::Cache::Adapters::RedisAdapter) && @config.impressions_mode != :none &&
|
|
119
120
|
(!@impressions_repository.empty? || !@events_repository.empty?)
|
|
120
|
-
@config.logger.debug("Impressions and/or Events cache is not empty")
|
|
121
|
+
@config.logger.debug("Impressions and/or Events cache is not empty") if @config.debug_enabled
|
|
121
122
|
# Adding small delay to ensure sender threads are fully running
|
|
122
123
|
sleep(0.1)
|
|
123
124
|
if !@config.threads.key?(:impressions_sender) || !@config.threads.key?(:events_sender)
|
|
124
|
-
@config.logger.debug("Periodic data recording thread has not started yet, waiting for service startup.")
|
|
125
|
+
@config.logger.debug("Periodic data recording thread has not started yet, waiting for service startup.") if @config.debug_enabled
|
|
125
126
|
@config.threads[:start_sdk].join(5) if @config.threads.key?(:start_sdk)
|
|
126
127
|
end
|
|
127
128
|
end
|
|
@@ -176,6 +177,14 @@ module SplitIoClient
|
|
|
176
177
|
@status_manager.wait_until_ready(time) if @status_manager
|
|
177
178
|
end
|
|
178
179
|
|
|
180
|
+
def register(sdk_event, handler)
|
|
181
|
+
@events_manager.register(sdk_event, handler)
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
def unregister(sdk_event, handler)
|
|
185
|
+
@events_manager.unregister(sdk_event)
|
|
186
|
+
end
|
|
187
|
+
|
|
179
188
|
private
|
|
180
189
|
|
|
181
190
|
def check_properties_size(properties_size, msg = "Event not queued")
|
|
@@ -24,7 +24,7 @@ module SplitIoClient
|
|
|
24
24
|
|
|
25
25
|
if check_last_proxy_check_timestamp
|
|
26
26
|
@spec_version = SplitIoClient::Spec::FeatureFlags::SPEC_VERSION
|
|
27
|
-
@config.logger.debug("Switching to new Feature flag spec #{@spec_version} and fetching.")
|
|
27
|
+
@config.logger.debug("Switching to new Feature flag spec #{@spec_version} and fetching.") if @config.debug_enabled
|
|
28
28
|
@old_spec_since = since
|
|
29
29
|
since = -1
|
|
30
30
|
since_rbs = -1
|
|
@@ -41,7 +41,7 @@ module SplitIoClient
|
|
|
41
41
|
|
|
42
42
|
params[:sets] = @flag_sets_filter.join(",") unless @flag_sets_filter.empty?
|
|
43
43
|
params[:till] = fetch_options[:till] unless fetch_options[:till].nil?
|
|
44
|
-
@config.logger.debug("Fetching from splitChanges with #{params}: ")
|
|
44
|
+
@config.logger.debug("Fetching from splitChanges with #{params}: ") if @config.debug_enabled
|
|
45
45
|
response = get_api("#{@config.base_uri}/splitChanges", @api_key, params, fetch_options[:cache_control_headers])
|
|
46
46
|
if response.status == 414
|
|
47
47
|
@config.logger.error("Error fetching feature flags; the amount of flag sets provided are too big, causing uri length error.")
|
|
@@ -21,10 +21,12 @@ module SplitIoClient
|
|
|
21
21
|
return process_error(response) if response.status >= 400 && response.status < 500
|
|
22
22
|
|
|
23
23
|
@telemetry_runtime_producer.record_sync_error(Telemetry::Domain::Constants::TOKEN_SYNC, response.status.to_i)
|
|
24
|
-
|
|
24
|
+
if @config.debug_enabled
|
|
25
|
+
@config.logger.debug("Error connecting to: #{@config.auth_service_url}. Response status: #{response.status}")
|
|
26
|
+
end
|
|
25
27
|
{ push_enabled: false, retry: true }
|
|
26
28
|
rescue StandardError => e
|
|
27
|
-
@config.logger.debug("AuthApiClient error: #{e.inspect}.")
|
|
29
|
+
@config.logger.debug("AuthApiClient error: #{e.inspect}.") if @config.debug_enabled
|
|
28
30
|
{ push_enabled: false, retry: false }
|
|
29
31
|
end
|
|
30
32
|
|
|
@@ -51,7 +53,9 @@ module SplitIoClient
|
|
|
51
53
|
end
|
|
52
54
|
|
|
53
55
|
def process_error(response)
|
|
54
|
-
|
|
56
|
+
if @config.debug_enabled
|
|
57
|
+
@config.logger.debug("Error connecting to: #{@config.auth_service_url}. Response status: #{response.status}")
|
|
58
|
+
end
|
|
55
59
|
@telemetry_runtime_producer.record_auth_rejections if response.status == 401
|
|
56
60
|
|
|
57
61
|
{ push_enabled: false, retry: false }
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module SplitIoClient
|
|
4
|
+
module Engine
|
|
5
|
+
module Events
|
|
6
|
+
class EventsDelivery
|
|
7
|
+
def initialize(config)
|
|
8
|
+
@config = config
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def deliver(sdk_event, event_metadata, event_handler)
|
|
12
|
+
event_handler.call(event_metadata)
|
|
13
|
+
rescue StandardError => e
|
|
14
|
+
@config.logger.error("Exception when calling handler for Sdk Event #{sdk_event}")
|
|
15
|
+
@config.log_found_exception(__method__.to_s, e)
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module SplitIoClient
|
|
4
|
+
module Engine
|
|
5
|
+
module Events
|
|
6
|
+
class EventsManager
|
|
7
|
+
def initialize(events_manager_config, events_delivery, config)
|
|
8
|
+
@manager_config = events_manager_config
|
|
9
|
+
@events_delivery = events_delivery
|
|
10
|
+
@active_subscriptions = {}
|
|
11
|
+
@internal_events_status = {}
|
|
12
|
+
@mutex = Mutex.new
|
|
13
|
+
@config = config
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def register(sdk_event, event_handler)
|
|
17
|
+
return if @active_subscriptions.key?(sdk_event) && !get_event_handler(sdk_event).nil?
|
|
18
|
+
|
|
19
|
+
@mutex.synchronize do
|
|
20
|
+
# SDK ready already fired
|
|
21
|
+
if sdk_event == Engine::Models::SdkEvent::SDK_READY && event_already_triggered(sdk_event)
|
|
22
|
+
@active_subscriptions[sdk_event] = Engine::Models::EventActiveSubscriptions.new(true, event_handler)
|
|
23
|
+
@config.logger.debug('EventsManager: Firing SDK_READY event for new subscription') if @config.debug_enabled
|
|
24
|
+
fire_sdk_event(sdk_event, nil)
|
|
25
|
+
return
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
@config.logger.debug("EventsManager: Register event: #{sdk_event}") if @config.debug_enabled
|
|
29
|
+
@active_subscriptions[sdk_event] = Engine::Models::EventActiveSubscriptions.new(false, event_handler)
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def unregister(sdk_event)
|
|
34
|
+
return unless @active_subscriptions.key?(sdk_event)
|
|
35
|
+
|
|
36
|
+
@mutex.synchronize do
|
|
37
|
+
@active_subscriptions.delete(sdk_event)
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def notify_internal_event(sdk_internal_event, event_metadata)
|
|
42
|
+
@mutex.synchronize do
|
|
43
|
+
update_internal_event_status(sdk_internal_event, true)
|
|
44
|
+
@manager_config.evaluation_order.each do |sorted_event|
|
|
45
|
+
if get_sdk_event_if_applicable(sdk_internal_event).include?(sorted_event) &&
|
|
46
|
+
!get_event_handler(sorted_event).nil?
|
|
47
|
+
fire_sdk_event(sorted_event, event_metadata)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# if client is not subscribed to SDK_READY
|
|
51
|
+
if check_if_register_needed(sorted_event)
|
|
52
|
+
@config.logger.debug('EventsManager: Registering SDK_READY event as fired') if @config.debug_enabled
|
|
53
|
+
@active_subscriptions[Engine::Models::SdkEvent::SDK_READY] = Engine::Models::EventActiveSubscriptions.new(true, nil)
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def destroy
|
|
60
|
+
@mutex.synchronize do
|
|
61
|
+
@active_subscriptions = {}
|
|
62
|
+
@internal_events_status = {}
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
private
|
|
67
|
+
|
|
68
|
+
def check_if_register_needed(sorted_event)
|
|
69
|
+
sorted_event == Engine::Models::SdkEvent::SDK_READY &&
|
|
70
|
+
get_event_handler(sorted_event).nil? &&
|
|
71
|
+
!@active_subscriptions.include?(sorted_event)
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def fire_sdk_event(sdk_event, event_metadata)
|
|
75
|
+
@config.logger.debug("EventsManager: Firing Sdk event: #{sdk_event}") if @config.debug_enabled
|
|
76
|
+
@config.threads[:sdk_event_notify] = Thread.new do
|
|
77
|
+
@events_delivery.deliver(sdk_event, event_metadata, get_event_handler(sdk_event))
|
|
78
|
+
end
|
|
79
|
+
sdk_event_triggered(sdk_event)
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def event_already_triggered(sdk_event)
|
|
83
|
+
return @active_subscriptions[sdk_event].triggered if @active_subscriptions.key?(sdk_event)
|
|
84
|
+
|
|
85
|
+
false
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def get_internal_event_status(sdk_internal_event)
|
|
89
|
+
return @internal_events_status[sdk_internal_event] if @internal_events_status.key?(sdk_internal_event)
|
|
90
|
+
|
|
91
|
+
false
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def update_internal_event_status(sdk_internal_event, status)
|
|
95
|
+
@internal_events_status[sdk_internal_event] = status
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def sdk_event_triggered(sdk_event)
|
|
99
|
+
return unless @active_subscriptions.key?(sdk_event)
|
|
100
|
+
|
|
101
|
+
return if @active_subscriptions[sdk_event].triggered
|
|
102
|
+
|
|
103
|
+
@active_subscriptions[sdk_event].triggered = true
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def get_event_handler(sdk_event)
|
|
107
|
+
return nil unless @active_subscriptions.key?(sdk_event)
|
|
108
|
+
|
|
109
|
+
@active_subscriptions[sdk_event].handler
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def get_sdk_event_if_applicable(sdk_internal_event)
|
|
113
|
+
final_sdk_event = Engine::Models::ValidSdkEvent.new(nil, false)
|
|
114
|
+
|
|
115
|
+
events_to_fire = []
|
|
116
|
+
require_any_sdk_event = check_require_any(sdk_internal_event)
|
|
117
|
+
if require_any_sdk_event.valid
|
|
118
|
+
if (!event_already_triggered(require_any_sdk_event.sdk_event) &&
|
|
119
|
+
execution_limit(require_any_sdk_event.sdk_event) == 1) ||
|
|
120
|
+
execution_limit(require_any_sdk_event.sdk_event) == -1
|
|
121
|
+
final_sdk_event = Engine::Models::ValidSdkEvent.new(
|
|
122
|
+
require_any_sdk_event.sdk_event,
|
|
123
|
+
check_prerequisites(require_any_sdk_event.sdk_event) &&
|
|
124
|
+
check_suppressed_by(require_any_sdk_event.sdk_event)
|
|
125
|
+
)
|
|
126
|
+
end
|
|
127
|
+
events_to_fire.push(final_sdk_event.sdk_event) if final_sdk_event.valid
|
|
128
|
+
end
|
|
129
|
+
check_require_all.each { |sdk_event| events_to_fire.push(sdk_event) }
|
|
130
|
+
|
|
131
|
+
events_to_fire
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
def check_require_all
|
|
135
|
+
events = []
|
|
136
|
+
@manager_config.require_all.each do |require_name, require_value|
|
|
137
|
+
final_status = true
|
|
138
|
+
require_value.each { |val| final_status &= get_internal_event_status(val) }
|
|
139
|
+
events.push(require_name) if check_event_eligible_conditions(final_status, require_name, require_value)
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
events
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
def check_event_eligible_conditions(final_status, require_name, require_value)
|
|
146
|
+
final_status &&
|
|
147
|
+
check_prerequisites(require_name) &&
|
|
148
|
+
((!event_already_triggered(require_name) &&
|
|
149
|
+
execution_limit(require_name) == 1) ||
|
|
150
|
+
execution_limit(require_name) == -1) &&
|
|
151
|
+
require_value.length.positive?
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
def check_prerequisites(sdk_event)
|
|
155
|
+
@manager_config.prerequisites.each do |name, value|
|
|
156
|
+
value.each do |val|
|
|
157
|
+
return false if name == sdk_event && !event_already_triggered(val)
|
|
158
|
+
end
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
true
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
def check_suppressed_by(sdk_event)
|
|
165
|
+
@manager_config.suppressed_by.each do |name, value|
|
|
166
|
+
value.each do |val|
|
|
167
|
+
return false if name == sdk_event && event_already_triggered(val)
|
|
168
|
+
end
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
true
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
def execution_limit(sdk_event)
|
|
175
|
+
return -1 unless @manager_config.execution_limits.key?(sdk_event)
|
|
176
|
+
|
|
177
|
+
@manager_config.execution_limits[sdk_event]
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
def check_require_any(sdk_internal_event)
|
|
181
|
+
valid_sdk_event = Engine::Models::ValidSdkEvent.new(nil, false)
|
|
182
|
+
@manager_config.require_any.each do |name, val|
|
|
183
|
+
if val.include?(sdk_internal_event)
|
|
184
|
+
valid_sdk_event = Engine::Models::ValidSdkEvent.new(name, true)
|
|
185
|
+
return valid_sdk_event
|
|
186
|
+
end
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
valid_sdk_event
|
|
190
|
+
end
|
|
191
|
+
end
|
|
192
|
+
end
|
|
193
|
+
end
|
|
194
|
+
end
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module SplitIoClient
|
|
4
|
+
module Engine
|
|
5
|
+
module Events
|
|
6
|
+
class EventsManagerConfig
|
|
7
|
+
attr_accessor :require_all, :prerequisites, :require_any, :suppressed_by, :execution_limits, :evaluation_order
|
|
8
|
+
|
|
9
|
+
def initialize
|
|
10
|
+
@require_all = construct_require_all
|
|
11
|
+
@prerequisites = construct_prerequisites
|
|
12
|
+
@require_any = construct_require_any
|
|
13
|
+
@suppressed_by = construct_suppressed_by
|
|
14
|
+
@execution_limits = construct_execution_limits
|
|
15
|
+
@evaluation_order = construct_sorted_events
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
private
|
|
19
|
+
|
|
20
|
+
def construct_require_all
|
|
21
|
+
{
|
|
22
|
+
SplitIoClient::Engine::Models::SdkEvent::SDK_READY => Set.new([SplitIoClient::Engine::Models::SdkInternalEvent::SDK_READY])
|
|
23
|
+
}
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def construct_prerequisites
|
|
27
|
+
{
|
|
28
|
+
SplitIoClient::Engine::Models::SdkEvent::SDK_UPDATE => Set.new([SplitIoClient::Engine::Models::SdkEvent::SDK_READY])
|
|
29
|
+
}
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def construct_require_any
|
|
33
|
+
{
|
|
34
|
+
SplitIoClient::Engine::Models::SdkEvent::SDK_UPDATE => Set.new(
|
|
35
|
+
[
|
|
36
|
+
SplitIoClient::Engine::Models::SdkInternalEvent::FLAG_KILLED_NOTIFICATION,
|
|
37
|
+
SplitIoClient::Engine::Models::SdkInternalEvent::FLAGS_UPDATED,
|
|
38
|
+
SplitIoClient::Engine::Models::SdkInternalEvent::RB_SEGMENTS_UPDATED,
|
|
39
|
+
SplitIoClient::Engine::Models::SdkInternalEvent::SEGMENTS_UPDATED
|
|
40
|
+
]
|
|
41
|
+
)
|
|
42
|
+
}
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def construct_suppressed_by
|
|
46
|
+
{}
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def construct_execution_limits
|
|
50
|
+
{
|
|
51
|
+
SplitIoClient::Engine::Models::SdkEvent::SDK_READY => 1,
|
|
52
|
+
SplitIoClient::Engine::Models::SdkEvent::SDK_UPDATE => -1
|
|
53
|
+
}
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def construct_sorted_events
|
|
57
|
+
sorted_events = []
|
|
58
|
+
[SplitIoClient::Engine::Models::SdkEvent::SDK_READY, SplitIoClient::Engine::Models::SdkEvent::SDK_UPDATE].each do |sdk_event|
|
|
59
|
+
sorted_events = dfs_recursive(sdk_event, sorted_events)
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
sorted_events
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def dfs_recursive(sdk_event, added)
|
|
66
|
+
return added if added.include?(sdk_event)
|
|
67
|
+
|
|
68
|
+
get_dependencies(sdk_event).each do |dependent_event|
|
|
69
|
+
added = dfs_recursive(dependent_event, added)
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
added.push(sdk_event)
|
|
73
|
+
|
|
74
|
+
added
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def get_dependencies(sdk_event)
|
|
78
|
+
dependencies = Set.new
|
|
79
|
+
@prerequisites.each do |prerequisites_event_name, prerequisites_event_value|
|
|
80
|
+
next unless prerequisites_event_name == sdk_event
|
|
81
|
+
|
|
82
|
+
prerequisites_event_value.each do |prereq_event|
|
|
83
|
+
dependencies.add(prereq_event)
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
@suppressed_by.each do |suppressed_event_name, suppressed_event_value|
|
|
88
|
+
dependencies.add(suppressed_event_name) if suppressed_event_value.include?(sdk_event)
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
dependencies
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
end
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module SplitIoClient
|
|
4
|
+
module Engine
|
|
5
|
+
module Events
|
|
6
|
+
class EventsTask
|
|
7
|
+
attr_accessor :running
|
|
8
|
+
|
|
9
|
+
def initialize(notify_internal_events, internal_events_queue, config)
|
|
10
|
+
@notify_internal_events = notify_internal_events
|
|
11
|
+
@internal_events_queue = internal_events_queue
|
|
12
|
+
@config = config
|
|
13
|
+
@running = false
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def start
|
|
17
|
+
return if @running
|
|
18
|
+
|
|
19
|
+
@config.logger.info('Starting Internal Events Task.')
|
|
20
|
+
@running = true
|
|
21
|
+
@config.threads[:internal_events_task] = Thread.new do
|
|
22
|
+
worker_thread
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def stop
|
|
27
|
+
return unless @running
|
|
28
|
+
|
|
29
|
+
@config.logger.info('Stopping Internal Events Task.')
|
|
30
|
+
@running = false
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
private
|
|
34
|
+
|
|
35
|
+
def worker_thread
|
|
36
|
+
while (event = @internal_events_queue.pop)
|
|
37
|
+
break unless @running
|
|
38
|
+
|
|
39
|
+
@config.logger.debug("Processing sdk internal event: #{event.internal_event}") if @config.debug_enabled
|
|
40
|
+
begin
|
|
41
|
+
@notify_internal_events.call(event.internal_event, event.metadata)
|
|
42
|
+
rescue StandardError => e
|
|
43
|
+
@config.log_found_exception(__method__.to_s, e)
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# frozen_string_literal: false
|
|
2
|
+
|
|
3
|
+
module SplitIoClient
|
|
4
|
+
module Engine::Models
|
|
5
|
+
class EventActiveSubscriptions
|
|
6
|
+
attr_accessor :triggered, :handler
|
|
7
|
+
|
|
8
|
+
def initialize(triggered, handler)
|
|
9
|
+
@triggered = triggered
|
|
10
|
+
@handler = handler
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
class SplitIoClient::Engine::Models::SdkInternalEvent
|
|
2
|
+
SDK_READY = 'SDK_READY'
|
|
3
|
+
FLAGS_UPDATED = 'FLAGS_UPDATED'
|
|
4
|
+
FLAG_KILLED_NOTIFICATION = 'FLAG_KILLED_NOTIFICATION'
|
|
5
|
+
SEGMENTS_UPDATED = 'SEGMENTS_UPDATED'
|
|
6
|
+
RB_SEGMENTS_UPDATED = 'RB_SEGMENTS_UPDATED'
|
|
7
|
+
LARGE_SEGMENTS_UPDATED = 'LARGE_SEGMENTS_UPDATED'
|
|
8
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# frozen_string_literal: false
|
|
2
|
+
|
|
3
|
+
module SplitIoClient
|
|
4
|
+
module Engine
|
|
5
|
+
module Models
|
|
6
|
+
class SdkInternalEventNotification
|
|
7
|
+
attr_reader :internal_event, :metadata
|
|
8
|
+
|
|
9
|
+
def initialize(internal_event, metadata)
|
|
10
|
+
@internal_event = internal_event
|
|
11
|
+
@metadata = metadata
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -3,9 +3,10 @@
|
|
|
3
3
|
module SplitIoClient
|
|
4
4
|
module Engine
|
|
5
5
|
class StatusManager
|
|
6
|
-
def initialize(config)
|
|
6
|
+
def initialize(config, internal_events_queue)
|
|
7
7
|
@config = config
|
|
8
8
|
@sdk_ready = Concurrent::CountDownLatch.new(1)
|
|
9
|
+
@internal_events_queue = internal_events_queue
|
|
9
10
|
end
|
|
10
11
|
|
|
11
12
|
def ready?
|
|
@@ -19,6 +20,11 @@ module SplitIoClient
|
|
|
19
20
|
|
|
20
21
|
@sdk_ready.count_down
|
|
21
22
|
@config.logger.info('SplitIO SDK is ready')
|
|
23
|
+
@internal_events_queue.push(
|
|
24
|
+
SplitIoClient::Engine::Models::SdkInternalEventNotification.new(
|
|
25
|
+
SplitIoClient::Engine::Models::SdkInternalEvent::SDK_READY, nil
|
|
26
|
+
)
|
|
27
|
+
)
|
|
22
28
|
end
|
|
23
29
|
|
|
24
30
|
def wait_until_ready(seconds = nil)
|
|
@@ -47,13 +47,13 @@ module SplitIoClient
|
|
|
47
47
|
connected = false
|
|
48
48
|
|
|
49
49
|
if @config.streaming_enabled
|
|
50
|
-
@config.logger.debug('Starting Streaming mode ...')
|
|
50
|
+
@config.logger.debug('Starting Streaming mode ...') if @config.debug_enabled
|
|
51
51
|
start_push_status_monitor
|
|
52
52
|
connected = @push_manager.start_sse
|
|
53
53
|
end
|
|
54
54
|
|
|
55
55
|
unless connected
|
|
56
|
-
@config.logger.debug('Starting Polling mode ...')
|
|
56
|
+
@config.logger.debug('Starting Polling mode ...') if @config.debug_enabled
|
|
57
57
|
@synchronizer.start_periodic_fetch
|
|
58
58
|
record_telemetry(Telemetry::Domain::Constants::SYNC_MODE, SYNC_MODE_POLLING)
|
|
59
59
|
end
|
|
@@ -92,7 +92,7 @@ module SplitIoClient
|
|
|
92
92
|
|
|
93
93
|
def process_connected
|
|
94
94
|
if @sse_connected.value
|
|
95
|
-
@config.logger.debug('Streaming already connected.')
|
|
95
|
+
@config.logger.debug('Streaming already connected.') if @config.debug_enabled
|
|
96
96
|
return
|
|
97
97
|
end
|
|
98
98
|
|
|
@@ -107,7 +107,7 @@ module SplitIoClient
|
|
|
107
107
|
|
|
108
108
|
def process_forced_stop
|
|
109
109
|
unless @sse_connected.value
|
|
110
|
-
@config.logger.debug('Streaming already disconnected.')
|
|
110
|
+
@config.logger.debug('Streaming already disconnected.') if @config.debug_enabled
|
|
111
111
|
return
|
|
112
112
|
end
|
|
113
113
|
|
|
@@ -120,7 +120,7 @@ module SplitIoClient
|
|
|
120
120
|
|
|
121
121
|
def process_disconnect(reconnect)
|
|
122
122
|
unless @sse_connected.value
|
|
123
|
-
@config.logger.debug('Streaming already disconnected.')
|
|
123
|
+
@config.logger.debug('Streaming already disconnected.') if @config.debug_enabled
|
|
124
124
|
return
|
|
125
125
|
end
|
|
126
126
|
|
|
@@ -169,12 +169,16 @@ module SplitIoClient
|
|
|
169
169
|
when Constants::PUSH_SUBSYSTEM_OFF
|
|
170
170
|
process_push_shutdown
|
|
171
171
|
else
|
|
172
|
-
|
|
172
|
+
log_if_debug('Incorrect push status type.')
|
|
173
173
|
end
|
|
174
174
|
end
|
|
175
175
|
rescue StandardError => e
|
|
176
176
|
@config.logger.error("Push status handler error: #{e.inspect}")
|
|
177
177
|
end
|
|
178
178
|
end
|
|
179
|
+
|
|
180
|
+
def log_if_debug(msg)
|
|
181
|
+
@config.logger.debug(msg) if @config.debug_enabled
|
|
182
|
+
end
|
|
179
183
|
end
|
|
180
184
|
end
|
|
@@ -45,6 +45,7 @@ module SplitIoClient
|
|
|
45
45
|
|
|
46
46
|
register_factory
|
|
47
47
|
|
|
48
|
+
build_events_manager
|
|
48
49
|
build_telemetry_components
|
|
49
50
|
build_flag_sets_filter
|
|
50
51
|
build_repositories
|
|
@@ -53,13 +54,13 @@ module SplitIoClient
|
|
|
53
54
|
build_unique_keys_tracker
|
|
54
55
|
build_impressions_components
|
|
55
56
|
|
|
56
|
-
@status_manager = Engine::StatusManager.new(@config)
|
|
57
|
+
@status_manager = Engine::StatusManager.new(@config, @internal_events_queue)
|
|
57
58
|
@split_validator = SplitIoClient::Validators.new(@config)
|
|
58
59
|
@evaluator = Engine::Parser::Evaluator.new(@segments_repository, @splits_repository, @rule_based_segment_repository, @config)
|
|
59
60
|
|
|
60
61
|
start!
|
|
61
62
|
fallback_treatment_calculator = SplitIoClient::Engine::FallbackTreatmentCalculator.new(@config.fallback_treatments_configuration)
|
|
62
|
-
@client = SplitClient.new(@api_key, repositories, @status_manager, @config, @impressions_manager, @evaluation_producer, @evaluator, @split_validator, fallback_treatment_calculator)
|
|
63
|
+
@client = SplitClient.new(@api_key, repositories, @status_manager, @config, @impressions_manager, @evaluation_producer, @evaluator, @split_validator, fallback_treatment_calculator, @events_manager)
|
|
63
64
|
@manager = SplitManager.new(@splits_repository, @status_manager, @config)
|
|
64
65
|
end
|
|
65
66
|
|
|
@@ -219,9 +220,9 @@ module SplitIoClient
|
|
|
219
220
|
else
|
|
220
221
|
@flag_sets_repository = SplitIoClient::Cache::Repositories::MemoryFlagSetsRepository.new(@config.flag_sets_filter)
|
|
221
222
|
end
|
|
222
|
-
@splits_repository = SplitsRepository.new(@config, @flag_sets_repository, @flag_sets_filter)
|
|
223
|
-
@segments_repository = SegmentsRepository.new(@config)
|
|
224
|
-
@rule_based_segment_repository = RuleBasedSegmentsRepository.new(@config)
|
|
223
|
+
@splits_repository = SplitsRepository.new(@config, @flag_sets_repository, @flag_sets_filter, @internal_events_queue)
|
|
224
|
+
@segments_repository = SegmentsRepository.new(@config, @internal_events_queue)
|
|
225
|
+
@rule_based_segment_repository = RuleBasedSegmentsRepository.new(@config, @internal_events_queue)
|
|
225
226
|
@impressions_repository = ImpressionsRepository.new(@config)
|
|
226
227
|
@events_repository = EventsRepository.new(@config, @api_key, @runtime_producer)
|
|
227
228
|
end
|
|
@@ -265,5 +266,19 @@ module SplitIoClient
|
|
|
265
266
|
def build_flag_sets_filter
|
|
266
267
|
@flag_sets_filter = SplitIoClient::Cache::Filter::FlagSetsFilter.new(@config.flag_sets_filter)
|
|
267
268
|
end
|
|
269
|
+
|
|
270
|
+
def build_events_manager
|
|
271
|
+
@events_manager = Engine::Events::EventsManager.new(Engine::Events::EventsManagerConfig.new,
|
|
272
|
+
Engine::Events::EventsDelivery.new(@config),
|
|
273
|
+
@config)
|
|
274
|
+
if @config.consumer?
|
|
275
|
+
@internal_events_queue = Engine::Events::NoOpEventsQueue.new
|
|
276
|
+
return
|
|
277
|
+
end
|
|
278
|
+
|
|
279
|
+
@internal_events_queue = Queue.new
|
|
280
|
+
@events_task = Engine::Events::EventsTask.new(@events_manager.method(:notify_internal_event), @internal_events_queue, @config)
|
|
281
|
+
@events_task.start
|
|
282
|
+
end
|
|
268
283
|
end
|
|
269
284
|
end
|
|
@@ -38,23 +38,23 @@ module SplitIoClient
|
|
|
38
38
|
|
|
39
39
|
def close(status = nil)
|
|
40
40
|
unless connected?
|
|
41
|
-
@config.logger.debug('SSEClient already disconected.')
|
|
41
|
+
@config.logger.debug('SSEClient already disconected.') if @config.debug_enabled
|
|
42
42
|
return
|
|
43
43
|
end
|
|
44
|
-
@config.logger.debug("Closing SSEClient socket")
|
|
44
|
+
@config.logger.debug("Closing SSEClient socket") if @config.debug_enabled
|
|
45
45
|
|
|
46
|
+
push_status(status)
|
|
46
47
|
@connected.make_false
|
|
47
48
|
@socket.sync_close = true if @socket.is_a? OpenSSL::SSL::SSLSocket
|
|
48
49
|
@socket.close
|
|
49
|
-
@config.logger.debug("SSEClient socket state #{@socket.state}") if @socket.is_a? OpenSSL::SSL::SSLSocket
|
|
50
|
-
push_status(status)
|
|
50
|
+
@config.logger.debug("SSEClient socket state #{@socket.state}") if @socket.is_a? OpenSSL::SSL::SSLSocket && @config.debug_enabled
|
|
51
51
|
rescue StandardError => e
|
|
52
52
|
@config.logger.error("SSEClient close Error: #{e.inspect}")
|
|
53
53
|
end
|
|
54
54
|
|
|
55
55
|
def start(url)
|
|
56
56
|
if connected?
|
|
57
|
-
@config.logger.debug('SSEClient already running.')
|
|
57
|
+
@config.logger.debug('SSEClient already running.') if @config.debug_enabled
|
|
58
58
|
return true
|
|
59
59
|
end
|
|
60
60
|
|
|
@@ -96,18 +96,17 @@ module SplitIoClient
|
|
|
96
96
|
|
|
97
97
|
raise 'eof exception' if partial_data == :eof
|
|
98
98
|
rescue IO::WaitReadable => e
|
|
99
|
-
@config.logger.debug("SSE client IO::WaitReadable transient error: #{e.inspect}")
|
|
99
|
+
@config.logger.debug("SSE client IO::WaitReadable transient error: #{e.inspect}") if @config.debug_enabled
|
|
100
100
|
IO.select([@socket], nil, nil, @read_timeout)
|
|
101
101
|
retry
|
|
102
102
|
rescue Errno::EAGAIN => e
|
|
103
|
-
@config.logger.debug("SSE client transient error: #{e.inspect}")
|
|
103
|
+
@config.logger.debug("SSE client transient error: #{e.inspect}") if @config.debug_enabled
|
|
104
104
|
IO.select([@socket], nil, nil, @read_timeout)
|
|
105
105
|
retry
|
|
106
106
|
rescue Errno::ETIMEDOUT => e
|
|
107
107
|
@config.logger.error("SSE read operation timed out!: #{e.inspect}")
|
|
108
108
|
return Constants::PUSH_RETRYABLE_ERROR
|
|
109
109
|
rescue EOFError => e
|
|
110
|
-
puts "SSE read operation EOF Exception!: #{e.inspect}"
|
|
111
110
|
@config.logger.error("SSE read operation EOF Exception!: #{e.inspect}")
|
|
112
111
|
raise 'eof exception'
|
|
113
112
|
rescue Errno::EBADF, IOError => e
|
|
@@ -125,12 +124,12 @@ module SplitIoClient
|
|
|
125
124
|
return Constants::PUSH_RETRYABLE_ERROR
|
|
126
125
|
end
|
|
127
126
|
rescue Errno::EBADF
|
|
128
|
-
@config.logger.debug("SSE socket is not connected (Errno::EBADF)")
|
|
127
|
+
@config.logger.debug("SSE socket is not connected (Errno::EBADF)") if @config.debug_enabled
|
|
129
128
|
break
|
|
130
129
|
rescue RuntimeError
|
|
131
130
|
raise 'eof exception'
|
|
132
131
|
rescue Exception => e
|
|
133
|
-
@config.logger.debug("SSE socket is not connected: #{e.inspect}")
|
|
132
|
+
@config.logger.debug("SSE socket is not connected: #{e.inspect}") if @config.debug_enabled
|
|
134
133
|
break
|
|
135
134
|
end
|
|
136
135
|
|
|
@@ -156,7 +155,7 @@ module SplitIoClient
|
|
|
156
155
|
return unless @first_event.value
|
|
157
156
|
|
|
158
157
|
response_code = @event_parser.first_event(data)
|
|
159
|
-
@config.logger.debug("SSE client first event code: #{response_code}")
|
|
158
|
+
@config.logger.debug("SSE client first event code: #{response_code}") if @config.debug_enabled
|
|
160
159
|
|
|
161
160
|
error_event = false
|
|
162
161
|
events = @event_parser.parse(data)
|
|
@@ -165,7 +164,7 @@ module SplitIoClient
|
|
|
165
164
|
|
|
166
165
|
if response_code == OK_CODE && !error_event
|
|
167
166
|
@connected.make_true
|
|
168
|
-
@config.logger.debug("SSE client first event Connected is true")
|
|
167
|
+
@config.logger.debug("SSE client first event Connected is true") if @config.debug_enabled
|
|
169
168
|
@telemetry_runtime_producer.record_streaming_event(Telemetry::Domain::Constants::SSE_CONNECTION_ESTABLISHED, nil)
|
|
170
169
|
push_status(Constants::PUSH_CONNECTED)
|
|
171
170
|
end
|
|
@@ -202,7 +201,7 @@ module SplitIoClient
|
|
|
202
201
|
end
|
|
203
202
|
|
|
204
203
|
def process_data(partial_data)
|
|
205
|
-
@config.logger.debug("Event partial data: #{partial_data}")
|
|
204
|
+
@config.logger.debug("Event partial data: #{partial_data}") if @config.debug_enabled
|
|
206
205
|
return if partial_data.nil? || partial_data == KEEP_ALIVE_RESPONSE
|
|
207
206
|
|
|
208
207
|
events = @event_parser.parse(partial_data)
|
|
@@ -220,7 +219,7 @@ module SplitIoClient
|
|
|
220
219
|
req << "SplitSDKMachineName: #{@config.machine_name}\r\n"
|
|
221
220
|
req << "SplitSDKClientKey: #{@api_key.split(//).last(4).join}\r\n" unless @api_key.nil?
|
|
222
221
|
req << "Cache-Control: no-cache\r\n\r\n"
|
|
223
|
-
@config.logger.debug("Request info: #{req}")
|
|
222
|
+
@config.logger.debug("Request info: #{req}") if @config.debug_enabled
|
|
224
223
|
req
|
|
225
224
|
end
|
|
226
225
|
|
|
@@ -255,7 +254,7 @@ module SplitIoClient
|
|
|
255
254
|
def push_status(status)
|
|
256
255
|
return if status.nil?
|
|
257
256
|
|
|
258
|
-
@config.logger.debug("Pushing new sse status: #{status}")
|
|
257
|
+
@config.logger.debug("Pushing new sse status: #{status}") if @config.debug_enabled
|
|
259
258
|
@status_queue.push(status)
|
|
260
259
|
end
|
|
261
260
|
end
|
|
@@ -29,14 +29,14 @@ module SplitIoClient
|
|
|
29
29
|
|
|
30
30
|
events
|
|
31
31
|
rescue StandardError => e
|
|
32
|
-
@config.logger.debug("Error during parsing a event: #{e.inspect}")
|
|
32
|
+
@config.logger.debug("Error during parsing a event: #{e.inspect}") if @config.debug_enabled
|
|
33
33
|
[]
|
|
34
34
|
end
|
|
35
35
|
|
|
36
36
|
def first_event(raw_data)
|
|
37
37
|
raw_data.split("\n")[0].split(' ')[1].to_i
|
|
38
38
|
rescue StandardError => e
|
|
39
|
-
@config.logger.
|
|
39
|
+
@config.logger.error("Error parsing first event: #{e.inspect}")
|
|
40
40
|
BAD_REQUEST_CODE
|
|
41
41
|
end
|
|
42
42
|
|
|
@@ -42,12 +42,12 @@ module SplitIoClient
|
|
|
42
42
|
@telemetry_runtime_producer.record_streaming_event(Telemetry::Domain::Constants::STREAMING_STATUS, DISABLED)
|
|
43
43
|
push_status(Constants::PUSH_SUBSYSTEM_OFF)
|
|
44
44
|
else
|
|
45
|
-
@config.logger.error("Incorrect event type: #{incoming_notification}")
|
|
45
|
+
@config.logger.error("Incorrect event type: #{incoming_notification}") if @config.debug_enabled
|
|
46
46
|
end
|
|
47
47
|
end
|
|
48
48
|
|
|
49
49
|
def process_event_occupancy(channel, publishers)
|
|
50
|
-
@config.logger.debug("Processed occupancy event with #{publishers} publishers. Channel: #{channel}")
|
|
50
|
+
@config.logger.debug("Processed occupancy event with #{publishers} publishers. Channel: #{channel}") if @config.debug_enabled
|
|
51
51
|
|
|
52
52
|
update_publishers(channel, publishers)
|
|
53
53
|
|
|
@@ -76,7 +76,7 @@ module SplitIoClient
|
|
|
76
76
|
end
|
|
77
77
|
|
|
78
78
|
def push_status(status)
|
|
79
|
-
@config.logger.debug("Pushing occupancy status: #{status}")
|
|
79
|
+
@config.logger.debug("Pushing occupancy status: #{status}") if @config.debug_enabled
|
|
80
80
|
@status_queue.push(status)
|
|
81
81
|
end
|
|
82
82
|
end
|
|
@@ -14,13 +14,13 @@ module SplitIoClient
|
|
|
14
14
|
|
|
15
15
|
def add_to_queue(change_number, segment_name)
|
|
16
16
|
item = { change_number: change_number, segment_name: segment_name }
|
|
17
|
-
@config.logger.debug("SegmentsWorker add to queue #{item}")
|
|
17
|
+
@config.logger.debug("SegmentsWorker add to queue #{item}") if @config.debug_enabled
|
|
18
18
|
@queue.push(item)
|
|
19
19
|
end
|
|
20
20
|
|
|
21
21
|
def start
|
|
22
22
|
if @running.value
|
|
23
|
-
@config.logger.debug('segments worker already running.')
|
|
23
|
+
@config.logger.debug('segments worker already running.') if @config.debug_enabled
|
|
24
24
|
return
|
|
25
25
|
end
|
|
26
26
|
|
|
@@ -30,7 +30,7 @@ module SplitIoClient
|
|
|
30
30
|
|
|
31
31
|
def stop
|
|
32
32
|
unless @running.value
|
|
33
|
-
@config.logger.debug('segments worker not running.')
|
|
33
|
+
@config.logger.debug('segments worker not running.') if @config.debug_enabled
|
|
34
34
|
return
|
|
35
35
|
end
|
|
36
36
|
|
|
@@ -44,7 +44,7 @@ module SplitIoClient
|
|
|
44
44
|
while (item = @queue.pop)
|
|
45
45
|
segment_name = item[:segment_name]
|
|
46
46
|
cn = item[:change_number]
|
|
47
|
-
@config.logger.debug("SegmentsWorker change_number dequeue #{segment_name}, #{cn}")
|
|
47
|
+
@config.logger.debug("SegmentsWorker change_number dequeue #{segment_name}, #{cn}") if @config.debug_enabled
|
|
48
48
|
|
|
49
49
|
@synchronizer.fetch_segment(segment_name, cn)
|
|
50
50
|
end
|
|
@@ -18,7 +18,7 @@ module SplitIoClient
|
|
|
18
18
|
|
|
19
19
|
def start
|
|
20
20
|
if @running.value
|
|
21
|
-
@config.logger.debug('feature_flags_worker already running.')
|
|
21
|
+
@config.logger.debug('feature_flags_worker already running.') if @config.debug_enabled
|
|
22
22
|
return
|
|
23
23
|
end
|
|
24
24
|
|
|
@@ -28,7 +28,7 @@ module SplitIoClient
|
|
|
28
28
|
|
|
29
29
|
def stop
|
|
30
30
|
unless @running.value
|
|
31
|
-
@config.logger.debug('feature_flags_worker not running.')
|
|
31
|
+
@config.logger.debug('feature_flags_worker not running.') if @config.debug_enabled
|
|
32
32
|
return
|
|
33
33
|
end
|
|
34
34
|
|
|
@@ -37,7 +37,7 @@ module SplitIoClient
|
|
|
37
37
|
end
|
|
38
38
|
|
|
39
39
|
def add_to_queue(notification)
|
|
40
|
-
@config.logger.debug("feature_flags_worker add to queue #{notification.data['changeNumber']}")
|
|
40
|
+
@config.logger.debug("feature_flags_worker add to queue #{notification.data['changeNumber']}") if @config.debug_enabled
|
|
41
41
|
@queue.push(notification)
|
|
42
42
|
end
|
|
43
43
|
|
|
@@ -52,7 +52,9 @@ module SplitIoClient
|
|
|
52
52
|
|
|
53
53
|
def perform
|
|
54
54
|
while (notification = @queue.pop)
|
|
55
|
-
@config.
|
|
55
|
+
if @config.debug_enabled
|
|
56
|
+
@config.logger.debug("feature_flags_worker change_number dequeue #{notification.data['changeNumber']}")
|
|
57
|
+
end
|
|
56
58
|
case notification.data['type']
|
|
57
59
|
when SSE::EventSource::EventTypes::SPLIT_UPDATE
|
|
58
60
|
success = update_feature_flag(notification)
|
|
@@ -117,7 +119,9 @@ module SplitIoClient
|
|
|
117
119
|
def kill_feature_flag(notification)
|
|
118
120
|
return if @feature_flags_repository.get_change_number.to_i > notification.data['changeNumber']
|
|
119
121
|
|
|
120
|
-
@config.
|
|
122
|
+
if @config.debug_enabled
|
|
123
|
+
@config.logger.debug("feature_flags_worker kill #{notification.data['splitName']}, #{notification.data['changeNumber']}")
|
|
124
|
+
end
|
|
121
125
|
@feature_flags_repository.kill(notification.data['changeNumber'],
|
|
122
126
|
notification.data['splitName'],
|
|
123
127
|
notification.data['defaultTreatment'])
|
data/lib/splitclient-rb.rb
CHANGED
|
@@ -66,6 +66,11 @@ require 'splitclient-rb/engine/api/telemetry_api'
|
|
|
66
66
|
require 'splitclient-rb/engine/common/impressions_counter'
|
|
67
67
|
require 'splitclient-rb/engine/common/impressions_manager'
|
|
68
68
|
require 'splitclient-rb/engine/common/noop_impressions_counter'
|
|
69
|
+
require 'splitclient-rb/engine/events/events_manager_config.rb'
|
|
70
|
+
require 'splitclient-rb/engine/events/events_manager.rb'
|
|
71
|
+
require 'splitclient-rb/engine/events/events_task.rb'
|
|
72
|
+
require 'splitclient-rb/engine/events/events_delivery.rb'
|
|
73
|
+
require 'splitclient-rb/engine/events/noop_events_queue.rb'
|
|
69
74
|
require 'splitclient-rb/engine/parser/condition'
|
|
70
75
|
require 'splitclient-rb/engine/parser/partition'
|
|
71
76
|
require 'splitclient-rb/engine/parser/evaluator'
|
|
@@ -112,6 +117,13 @@ require 'splitclient-rb/engine/models/split_http_response'
|
|
|
112
117
|
require 'splitclient-rb/engine/models/evaluation_options'
|
|
113
118
|
require 'splitclient-rb/engine/models/fallback_treatment.rb'
|
|
114
119
|
require 'splitclient-rb/engine/models/fallback_treatments_configuration.rb'
|
|
120
|
+
require 'splitclient-rb/engine/models/events_metadata.rb'
|
|
121
|
+
require 'splitclient-rb/engine/models/sdk_event_type.rb'
|
|
122
|
+
require 'splitclient-rb/engine/models/sdk_event.rb'
|
|
123
|
+
require 'splitclient-rb/engine/models/sdk_internal_event.rb'
|
|
124
|
+
require 'splitclient-rb/engine/models/sdk_internal_event_notification.rb'
|
|
125
|
+
require 'splitclient-rb/engine/models/valid_sdk_event.rb'
|
|
126
|
+
require 'splitclient-rb/engine/models/event_active_subscriptions.rb'
|
|
115
127
|
require 'splitclient-rb/engine/auth_api_client'
|
|
116
128
|
require 'splitclient-rb/engine/back_off'
|
|
117
129
|
require 'splitclient-rb/engine/fallback_treatment_calculator.rb'
|
metadata
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: splitclient-rb
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 8.
|
|
4
|
+
version: 8.11.0
|
|
5
5
|
platform: java
|
|
6
6
|
authors:
|
|
7
7
|
- Split Software
|
|
8
8
|
bindir: bin
|
|
9
9
|
cert_chain: []
|
|
10
|
-
date: 2026-
|
|
10
|
+
date: 2026-03-12 00:00:00.000000000 Z
|
|
11
11
|
dependencies:
|
|
12
12
|
- !ruby/object:Gem::Dependency
|
|
13
13
|
name: allocation_stats
|
|
@@ -393,6 +393,7 @@ files:
|
|
|
393
393
|
- CONTRIBUTORS-GUIDE.md
|
|
394
394
|
- Gemfile
|
|
395
395
|
- LICENSE
|
|
396
|
+
- NOTICE.txt
|
|
396
397
|
- README.md
|
|
397
398
|
- Rakefile
|
|
398
399
|
- ext/murmurhash/MurmurHash3.java
|
|
@@ -454,6 +455,11 @@ files:
|
|
|
454
455
|
- lib/splitclient-rb/engine/common/impressions_manager.rb
|
|
455
456
|
- lib/splitclient-rb/engine/common/noop_impressions_counter.rb
|
|
456
457
|
- lib/splitclient-rb/engine/evaluator/splitter.rb
|
|
458
|
+
- lib/splitclient-rb/engine/events/events_delivery.rb
|
|
459
|
+
- lib/splitclient-rb/engine/events/events_manager.rb
|
|
460
|
+
- lib/splitclient-rb/engine/events/events_manager_config.rb
|
|
461
|
+
- lib/splitclient-rb/engine/events/events_task.rb
|
|
462
|
+
- lib/splitclient-rb/engine/events/noop_events_queue.rb
|
|
457
463
|
- lib/splitclient-rb/engine/fallback_treatment_calculator.rb
|
|
458
464
|
- lib/splitclient-rb/engine/impressions/noop_unique_keys_tracker.rb
|
|
459
465
|
- lib/splitclient-rb/engine/impressions/unique_keys_tracker.rb
|
|
@@ -489,13 +495,20 @@ files:
|
|
|
489
495
|
- lib/splitclient-rb/engine/matchers/whitelist_matcher.rb
|
|
490
496
|
- lib/splitclient-rb/engine/metrics/binary_search_latency_tracker.rb
|
|
491
497
|
- lib/splitclient-rb/engine/models/evaluation_options.rb
|
|
498
|
+
- lib/splitclient-rb/engine/models/event_active_subscriptions.rb
|
|
499
|
+
- lib/splitclient-rb/engine/models/events_metadata.rb
|
|
492
500
|
- lib/splitclient-rb/engine/models/fallback_treatment.rb
|
|
493
501
|
- lib/splitclient-rb/engine/models/fallback_treatments_configuration.rb
|
|
494
502
|
- lib/splitclient-rb/engine/models/label.rb
|
|
503
|
+
- lib/splitclient-rb/engine/models/sdk_event.rb
|
|
504
|
+
- lib/splitclient-rb/engine/models/sdk_event_type.rb
|
|
505
|
+
- lib/splitclient-rb/engine/models/sdk_internal_event.rb
|
|
506
|
+
- lib/splitclient-rb/engine/models/sdk_internal_event_notification.rb
|
|
495
507
|
- lib/splitclient-rb/engine/models/segment_type.rb
|
|
496
508
|
- lib/splitclient-rb/engine/models/split.rb
|
|
497
509
|
- lib/splitclient-rb/engine/models/split_http_response.rb
|
|
498
510
|
- lib/splitclient-rb/engine/models/treatment.rb
|
|
511
|
+
- lib/splitclient-rb/engine/models/valid_sdk_event.rb
|
|
499
512
|
- lib/splitclient-rb/engine/parser/condition.rb
|
|
500
513
|
- lib/splitclient-rb/engine/parser/evaluator.rb
|
|
501
514
|
- lib/splitclient-rb/engine/parser/partition.rb
|