Skip to content

Commit 1d6b7e6

Browse files
authored
Merge pull request #618 from splitio/feature/sdk-events
Prepare release 8.11.0
2 parents d9a1788 + 96d2fbd commit 1d6b7e6

File tree

58 files changed

+1220
-169
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

58 files changed

+1220
-169
lines changed

CHANGES.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
CHANGES
22

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+
38
8.10.1 (Jan 28, 2025)
49
- Fixed rule-based segment matcher to exit when a conition is met.
510
- Fixed impressions properties format in redis mode.

LICENSE

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ Apache License
157157
file or class name and description of purpose be included on the
158158
same "printed page" as the copyright notice for easier
159159
identification within third-party archives.
160-
Copyright [yyyy] [name of copyright owner]
160+
Copyright 2025 Harness Corporation
161161
Licensed under the Apache License, Version 2.0 (the "License");
162162
you may not use this file except in compliance with the License.
163163
You may obtain a copy of the License at

lib/splitclient-rb.rb

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,11 @@
6666
require 'splitclient-rb/engine/common/impressions_counter'
6767
require 'splitclient-rb/engine/common/impressions_manager'
6868
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'
6974
require 'splitclient-rb/engine/parser/condition'
7075
require 'splitclient-rb/engine/parser/partition'
7176
require 'splitclient-rb/engine/parser/evaluator'
@@ -112,6 +117,13 @@
112117
require 'splitclient-rb/engine/models/evaluation_options'
113118
require 'splitclient-rb/engine/models/fallback_treatment.rb'
114119
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'
115127
require 'splitclient-rb/engine/auth_api_client'
116128
require 'splitclient-rb/engine/back_off'
117129
require 'splitclient-rb/engine/fallback_treatment_calculator.rb'

lib/splitclient-rb/cache/repositories/rule_based_segments_repository.rb

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ class RuleBasedSegmentsRepository < Repository
2828
RB_SEGMENTS_PREFIX = '.rbsegment.'
2929
REGISTERED_PREFIX = '.segments.registered'
3030

31-
def initialize(config)
31+
def initialize(config, internal_events_queue)
3232
super(config)
3333
@adapter = case @config.cache_adapter.class.to_s
3434
when 'SplitIoClient::Cache::Adapters::RedisAdapter'
@@ -40,12 +40,25 @@ def initialize(config)
4040
@adapter.set_string(namespace_key(TILL_PREFIX), '-1')
4141
@adapter.initialize_map(namespace_key(REGISTERED_PREFIX))
4242
end
43+
@internal_events_queue = internal_events_queue
4344
end
4445

4546
def update(to_add, to_delete, new_change_number)
4647
to_add.each{ |rule_based_segment| add_rule_based_segment(rule_based_segment) }
4748
to_delete.each{ |rule_based_segment| remove_rule_based_segment(rule_based_segment) }
4849
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
4962
end
5063

5164
def get_rule_based_segment(name)

lib/splitclient-rb/cache/repositories/segments_repository.rb

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ class SegmentsRepository < Repository
66

77
attr_reader :adapter
88

9-
def initialize(config)
9+
def initialize(config, internal_events_queue)
1010
super(config)
1111
@adapter = case @config.cache_adapter.class.to_s
1212
when 'SplitIoClient::Cache::Adapters::RedisAdapter'
@@ -15,16 +15,27 @@ def initialize(config)
1515
@config.cache_adapter
1616
end
1717
@adapter.set_bool(namespace_key('.ready'), false) unless @config.mode.equal?(:consumer)
18+
@internal_events_queue = internal_events_queue
1819
end
1920

2021
# Receives segment data, adds and removes segements from the store
2122
def add_to_segment(segment)
2223
name = segment[:name]
2324

2425
@adapter.initialize_set(segment_data(name)) unless @adapter.exists?(segment_data(name))
25-
2626
add_keys(name, segment[:added])
2727
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
2839
end
2940

3041
def get_segment_keys(name)

lib/splitclient-rb/cache/repositories/splits_repository.rb

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ class SplitsRepository < Repository
3535
SPLIT_PREFIX = '.split.'
3636
READY_PREFIX = '.splits.ready'
3737

38-
def initialize(config, flag_sets_repository, flag_set_filter)
38+
def initialize(config, flag_sets_repository, flag_set_filter, internal_events_queue)
3939
super(config)
4040
@tt_cache = {}
4141
@adapter = case @config.cache_adapter.class.to_s
@@ -46,13 +46,26 @@ def initialize(config, flag_sets_repository, flag_set_filter)
4646
end
4747
@flag_sets = flag_sets_repository
4848
@flag_set_filter = flag_set_filter
49+
@internal_events_queue = internal_events_queue
4950
initialize_keys
5051
end
5152

5253
def update(to_add, to_delete, new_change_number)
5354
to_add.each{ |feature_flag| add_feature_flag(feature_flag) }
5455
to_delete.each{ |feature_flag| remove_feature_flag(feature_flag) }
5556
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
5669
end
5770

5871
def get_split(name)
@@ -140,6 +153,15 @@ def kill(change_number, split_name, default_treatment)
140153
split[:changeNumber] = change_number
141154

142155
@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+
)
143165
end
144166

145167
def splits_count

lib/splitclient-rb/clients/split_client.rb

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ class SplitClient
1818
# @param sdk_key [String] the SDK key for your split account
1919
#
2020
# @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)
2222
@api_key = sdk_key
2323
@splits_repository = repositories[:splits]
2424
@segments_repository = repositories[:segments]
@@ -33,6 +33,7 @@ def initialize(sdk_key, repositories, status_manager, config, impressions_manage
3333
@split_validator = split_validator
3434
@evaluator = evaluator
3535
@fallback_treatment_calculator = fallback_treatment_calculator
36+
@events_manager = events_manager
3637
end
3738

3839
def get_treatment(
@@ -117,11 +118,11 @@ def destroy
117118
@config.logger.info('Split client shutdown started...') if @config.debug_enabled
118119
if !@config.cache_adapter.is_a?(SplitIoClient::Cache::Adapters::RedisAdapter) && @config.impressions_mode != :none &&
119120
(!@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
121122
# Adding small delay to ensure sender threads are fully running
122123
sleep(0.1)
123124
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
125126
@config.threads[:start_sdk].join(5) if @config.threads.key?(:start_sdk)
126127
end
127128
end
@@ -176,6 +177,14 @@ def block_until_ready(time = nil)
176177
@status_manager.wait_until_ready(time) if @status_manager
177178
end
178179

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+
179188
private
180189

181190
def check_properties_size(properties_size, msg = "Event not queued")

lib/splitclient-rb/engine/api/faraday_middleware/gzip.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# frozen_string_literal: true
22

33
require 'faraday'
4+
require 'stringio'
45

56
module SplitIoClient
67
module FaradayMiddleware

lib/splitclient-rb/engine/api/splits.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ def since(since, since_rbs, fetch_options = { cache_control_headers: false, till
2424

2525
if check_last_proxy_check_timestamp
2626
@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
2828
@old_spec_since = since
2929
since = -1
3030
since_rbs = -1
@@ -41,7 +41,7 @@ def since(since, since_rbs, fetch_options = { cache_control_headers: false, till
4141

4242
params[:sets] = @flag_sets_filter.join(",") unless @flag_sets_filter.empty?
4343
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
4545
response = get_api("#{@config.base_uri}/splitChanges", @api_key, params, fetch_options[:cache_control_headers])
4646
if response.status == 414
4747
@config.logger.error("Error fetching feature flags; the amount of flag sets provided are too big, causing uri length error.")

lib/splitclient-rb/engine/auth_api_client.rb

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,12 @@ def authenticate(api_key)
2121
return process_error(response) if response.status >= 400 && response.status < 500
2222

2323
@telemetry_runtime_producer.record_sync_error(Telemetry::Domain::Constants::TOKEN_SYNC, response.status.to_i)
24-
@config.logger.debug("Error connecting to: #{@config.auth_service_url}. Response status: #{response.status}")
24+
if @config.debug_enabled
25+
@config.logger.debug("Error connecting to: #{@config.auth_service_url}. Response status: #{response.status}")
26+
end
2527
{ push_enabled: false, retry: true }
2628
rescue StandardError => e
27-
@config.logger.debug("AuthApiClient error: #{e.inspect}.")
29+
@config.logger.debug("AuthApiClient error: #{e.inspect}.") if @config.debug_enabled
2830
{ push_enabled: false, retry: false }
2931
end
3032

@@ -51,7 +53,9 @@ def decode_token(token)
5153
end
5254

5355
def process_error(response)
54-
@config.logger.debug("Error connecting to: #{@config.auth_service_url}. Response status: #{response.status}")
56+
if @config.debug_enabled
57+
@config.logger.debug("Error connecting to: #{@config.auth_service_url}. Response status: #{response.status}")
58+
end
5559
@telemetry_runtime_producer.record_auth_rejections if response.status == 401
5660

5761
{ push_enabled: false, retry: false }

0 commit comments

Comments
 (0)