Skip to content

Commit

Permalink
Merge branch 'development' into Feature/Semver
Browse files Browse the repository at this point in the history
  • Loading branch information
chillaq authored May 1, 2024
2 parents a1cab94 + 6eafede commit 0f5ac2f
Show file tree
Hide file tree
Showing 40 changed files with 397 additions and 258 deletions.
3 changes: 2 additions & 1 deletion CHANGES.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
CHANGES

Next release (TBD)
8.3.1 (Mar 22, 2024)
- Fixed ruby process hanging due to failed thread.join command, when calling destroy and a http request still active.
- Fixed streaming notification parser. Issue ref: https://github.com/splitio/ruby-client/issues/511

8.3.0 (Dec 11, 2023)
- Added support for Flag Sets on the SDK, which enables grouping feature flags and interacting with the group rather than individually (more details in our documentation):
Expand Down
2 changes: 2 additions & 0 deletions lib/splitclient-rb.rb
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,8 @@
require 'splitclient-rb/engine/synchronizer'
require 'splitclient-rb/utilitites'

require 'splitclient-rb/spec.rb'

# SSE
require 'splitclient-rb/sse/event_source/client'
require 'splitclient-rb/sse/event_source/event_parser'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@ def clear
@adapter.clear
end

def empty?
@adapter.empty?
end

def batch
return [] if @config.events_queue_size.zero?

Expand Down
4 changes: 4 additions & 0 deletions lib/splitclient-rb/cache/repositories/events_repository.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ def post_events
@config.log_found_exception(__method__.to_s, e)
end

def empty?
@repository.empty?
end

protected

def metadata
Expand Down
7 changes: 4 additions & 3 deletions lib/splitclient-rb/cache/repositories/splits_repository.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ module Cache
module Repositories
class SplitsRepository < Repository
attr_reader :adapter
DEFAULT_CONDITIONS_TEMPLATE = {
DEFAULT_CONDITIONS_TEMPLATE = [{
conditionType: "ROLLOUT",
matcherGroup: {
combiner: "AND",
Expand All @@ -30,7 +30,8 @@ class SplitsRepository < Repository
}
],
label: "unsupported matcher type"
}
}]

def initialize(config, flag_sets_repository, flag_set_filter)
super(config)
@tt_cache = {}
Expand Down Expand Up @@ -182,7 +183,7 @@ def add_feature_flag(split)

if check_undefined_matcher(split)
@config.logger.warn("Feature Flag #{split[:name]} has undefined matcher, setting conditions to default template.")
split[:conditions] = [SplitsRepository::DEFAULT_CONDITIONS_TEMPLATE]
split[:conditions] = SplitsRepository::DEFAULT_CONDITIONS_TEMPLATE
end
if !split[:sets].nil?
for flag_set in split[:sets]
Expand Down
11 changes: 10 additions & 1 deletion lib/splitclient-rb/clients/split_client.rb
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,16 @@ def get_treatments_with_config_by_flag_sets(key, flag_sets, attributes = {})

def destroy
@config.logger.info('Split client shutdown started...') if @config.debug_enabled

if !@config.cache_adapter.is_a?(SplitIoClient::Cache::Adapters::RedisAdapter) && @config.impressions_mode != :none &&
(!@impressions_repository.empty? || !@events_repository.empty?)
@config.logger.debug("Impressions and/or Events cache is not empty")
# Adding small delay to ensure sender threads are fully running
sleep(0.1)
if !@config.threads.key?(:impressions_sender) || !@config.threads.key?(:events_sender)
@config.logger.debug("Periodic data recording thread has not started yet, waiting for service startup.")
@config.threads[:start_sdk].join(5) if @config.threads.key?(:start_sdk)
end
end
@config.threads.select { |name, thread| name.to_s.end_with? 'sender' }.values.each do |thread|
thread.raise(SplitIoClient::SDKShutdownException)
thread.join
Expand Down
4 changes: 3 additions & 1 deletion lib/splitclient-rb/engine/api/client.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ def initialize(config)
end

def get_api(url, api_key, params = {}, cache_control_headers = false)
api_client.options.params_encoder.sort_params = false
api_client.get(url, params) do |req|
req.headers = common_headers(api_key).merge('Accept-Encoding' => 'gzip')
req.headers = req.headers.merge('Cache-Control' => 'no-cache') if cache_control_headers
Expand All @@ -29,7 +30,7 @@ def post_api(url, api_key, data, headers = {}, params = {})
req.headers = common_headers(api_key)
.merge('Content-Type' => 'application/json')
.merge(headers)

machine_ip = @config.machine_ip
machine_name = @config.machine_name

Expand All @@ -55,6 +56,7 @@ def api_client
@api_client ||= Faraday.new do |builder|
builder.use SplitIoClient::FaradayMiddleware::Gzip
builder.adapter :net_http_persistent
builder.options.params_encoder = Faraday::FlatParamsEncoder
end
end

Expand Down
5 changes: 3 additions & 2 deletions lib/splitclient-rb/engine/api/splits.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,18 @@ module SplitIoClient
module Api
# Retrieves split definitions from the Split Backend
class Splits < Client

def initialize(api_key, config, telemetry_runtime_producer)
super(config)
@api_key = api_key
@telemetry_runtime_producer = telemetry_runtime_producer
@flag_sets_filter = @config.flag_sets_filter
end

def since(since, fetch_options = { cache_control_headers: false, till: nil, sets: nil })
def since(since, fetch_options = { cache_control_headers: false, till: nil, sets: nil})
start = Time.now

params = { since: since }
params = { s: SplitIoClient::Spec::FeatureFlags::SPEC_VERSION, since: since }
params[:till] = fetch_options[:till] unless fetch_options[:till].nil?
params[:sets] = @flag_sets_filter.join(",") unless @flag_sets_filter.empty?
@config.logger.debug("Fetching from splitChanges with #{params}: ")
Expand Down
2 changes: 1 addition & 1 deletion lib/splitclient-rb/engine/auth_api_client.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ def initialize(config, telemetry_runtime_producer)

def authenticate(api_key)
start = Time.now
response = @api_client.get_api(@config.auth_service_url, api_key)
response = @api_client.get_api("#{@config.auth_service_url}?s=#{SplitIoClient::Spec::FeatureFlags::SPEC_VERSION}", api_key)

return process_success(response, start) if response.success?

Expand Down
9 changes: 9 additions & 0 deletions lib/splitclient-rb/spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# frozen_string_literal: true

module SplitIoClient
module Spec
class FeatureFlags
SPEC_VERSION = "1.1"
end
end
end
3 changes: 2 additions & 1 deletion lib/splitclient-rb/sse/event_source/event_parser.rb
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,8 @@ def first_event(raw_data)
private

def parse_event_data(data, type)
event_data = JSON.parse(data.sub('data: ', ''))
data_value = data.sub('data:', '')
event_data = JSON.parse(data_value.strip)
client_id = event_data['clientId']&.strip
channel = event_data['channel']&.strip
parsed_data = JSON.parse(event_data['data']) unless type == 'error'
Expand Down
4 changes: 2 additions & 2 deletions lib/splitclient-rb/sse/notification_manager_keeper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ def initialize(config, telemetry_runtime_producer, status_queue)
@telemetry_runtime_producer = telemetry_runtime_producer
@status_queue = status_queue
@publisher_available = Concurrent::AtomicBoolean.new(true)
@publishers_pri = Concurrent::AtomicFixnum.new
@publishers_sec = Concurrent::AtomicFixnum.new
@publishers_pri = Concurrent::AtomicFixnum.new(2)
@publishers_sec = Concurrent::AtomicFixnum.new(2)
end

def handle_incoming_occupancy_event(event)
Expand Down
2 changes: 1 addition & 1 deletion lib/splitclient-rb/version.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
module SplitIoClient
VERSION = '8.3.0'
VERSION = '8.3.1'
end
2 changes: 1 addition & 1 deletion spec/cache/fetchers/segment_fetch_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
stub_request(:get, 'https://sdk.split.io/api/segmentChanges/employees?since=1473863075059')
.to_return(status: 200, body: segments_json2)

stub_request(:get, 'https://sdk.split.io/api/splitChanges?since=-1')
stub_request(:get, 'https://sdk.split.io/api/splitChanges?s=1.1&since=-1')
.to_return(status: 200, body: splits_with_segments_json)
end

Expand Down
12 changes: 6 additions & 6 deletions spec/cache/fetchers/split_fetch_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
end

before do
stub_request(:get, 'https://sdk.split.io/api/splitChanges?since=-1')
stub_request(:get, 'https://sdk.split.io/api/splitChanges?s=1.1&since=-1')
.to_return(status: 200, body: active_splits_json)
end

Expand Down Expand Up @@ -48,7 +48,7 @@
active_split = store.splits_repository.splits['test_1_ruby']
expect(active_split[:status]).to eq('ACTIVE')

stub_request(:get, 'https://sdk.split.io/api/splitChanges?since=1473413807667')
stub_request(:get, 'https://sdk.split.io/api/splitChanges?s=1.1&since=1473413807667')
.to_return(status: 200, body: archived_splits_json)

store.send(:fetch_splits)
Expand Down Expand Up @@ -81,7 +81,7 @@
let(:store) { described_class.new(splits_repository, '', config, telemetry_runtime_producer) }

before do
stub_request(:get, 'https://sdk.split.io/api/splitChanges?sets=set_2&since=-1')
stub_request(:get, 'https://sdk.split.io/api/splitChanges?s=1.1&since=-1&sets=set_2')
.to_return(status: 200, body: active_splits_json)
end

Expand All @@ -103,14 +103,14 @@
expect(store.splits_repository.get_split('sample_feature')[:name]).to eq('sample_feature')
expect(store.splits_repository.get_split('test_1_ruby')).to eq(nil)

stub_request(:get, 'https://sdk.split.io/api/splitChanges?sets=set_2&since=1473413807667')
stub_request(:get, 'https://sdk.split.io/api/splitChanges?s=1.1&since=1473413807667&sets=set_2')
.to_return(status: 200, body: archived_splits_json)

store.send(:fetch_splits)
expect(store.splits_repository.get_split('sample_feature')).to eq(nil)

store.splits_repository.set_change_number(-1)
stub_request(:get, 'https://sdk.split.io/api/splitChanges?sets=set_2&since=-1')
stub_request(:get, 'https://sdk.split.io/api/splitChanges?s=1.1&since=-1&sets=set_2')
.to_return(status: 200, body: active_splits_json)

store.send(:fetch_splits)
Expand Down Expand Up @@ -149,7 +149,7 @@
active_split = store.splits_repository.splits['test_1_ruby']
expect(active_split[:status]).to eq('ACTIVE')

stub_request(:get, 'https://sdk.split.io/api/splitChanges?since=1473413807667')
stub_request(:get, 'https://sdk.split.io/api/splitChanges?s=1.1&since=1473413807667')
.to_return(status: 200, body: archived_splits_json)

store.send(:fetch_splits)
Expand Down
60 changes: 41 additions & 19 deletions spec/cache/repositories/splits_repository_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -126,29 +126,51 @@
}
}]
}
repository.update([split.dup], [], -1)
expect(repository.get_split('corge')[:conditions]).to eq [SplitIoClient::Cache::Repositories::SplitsRepository::DEFAULT_CONDITIONS_TEMPLATE]

repository.update([split], [], -1)
expect(repository.get_split('corge')[:conditions]).to eq SplitIoClient::Cache::Repositories::SplitsRepository::DEFAULT_CONDITIONS_TEMPLATE

# test with multiple conditions
split[:conditions] .append({
partitions: [
{treatment: 'on', size: 25},
{treatment: 'off', size: 75}
],
contitionType: 'WHITELIST',
label: 'some_other_label',
matcherGroup: {
matchers: [
{
matcherType: 'ALL_KEYS',
negate: false,
}
split2 = {
name: 'corge2',
trafficTypeName: 'tt_name_5',
conditions: [
{
partitions: [
{treatment: 'on', size: 50},
{treatment: 'off', size: 50}
],
contitionType: 'WHITELIST',
label: 'some_label',
matcherGroup: {
matchers: [
{
matcherType: 'UNDEFINED',
whitelistMatcherData: {
whitelist: ['k1', 'k2', 'k3']
},
negate: false,
}
],
combiner: 'AND'
}
},
{
partitions: [
{treatment: 'on', size: 25},
{treatment: 'off', size: 75}
],
combiner: 'AND'
contitionType: 'WHITELIST',
label: 'some_other_label',
matcherGroup: {
matchers: [{matcherType: 'ALL_KEYS', negate: false}],
combiner: 'AND'
}
}]
}
})
repository.update([split], [], -1)
expect(repository.get_split('corge')[:conditions]).to eq [SplitIoClient::Cache::Repositories::SplitsRepository::DEFAULT_CONDITIONS_TEMPLATE]

repository.update([split2], [], -1)
expect(repository.get_split('corge2')[:conditions]).to eq SplitIoClient::Cache::Repositories::SplitsRepository::DEFAULT_CONDITIONS_TEMPLATE
end
end

Expand Down
18 changes: 9 additions & 9 deletions spec/engine/api/splits_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
let(:splits_api) { described_class.new('', config, telemetry_runtime_producer) }

it 'returns splits with segment names' do
stub_request(:get, 'https://sdk.split.io/api/splitChanges?since=-1')
stub_request(:get, 'https://sdk.split.io/api/splitChanges?s=1.1&since=-1')
.to_return(status: 200, body: splits)

parsed_splits = splits_api.send(:splits_with_segment_names, splits)
Expand All @@ -41,7 +41,7 @@
let(:splits_api) { described_class.new('', config, telemetry_runtime_producer) }

it 'returns the splits - with 2 sets param' do
stub_request(:get, 'https://sdk.split.io/api/splitChanges?sets=set_1,set_2&since=-1')
stub_request(:get, 'https://sdk.split.io/api/splitChanges?s=1.1&since=-1&sets=set_1,set_2')
.with(headers: {
'Accept' => '*/*',
'Accept-Encoding' => 'gzip',
Expand All @@ -61,7 +61,7 @@
end

it 'raise api exception when status 414' do
stub_request(:get, 'https://sdk.split.io/api/splitChanges?sets=set_1,set_2&since=-1')
stub_request(:get, 'https://sdk.split.io/api/splitChanges?s=1.1&since=-1&sets=set_1,set_2')
.with(headers: {
'Accept' => '*/*',
'Accept-Encoding' => 'gzip',
Expand Down Expand Up @@ -96,7 +96,7 @@
let(:splits_api) { described_class.new('', config, telemetry_runtime_producer) }

it 'returns the splits - checking headers when cache_control_headers is false' do
stub_request(:get, 'https://sdk.split.io/api/splitChanges?since=-1')
stub_request(:get, 'https://sdk.split.io/api/splitChanges?s=1.1&since=-1')
.with(headers: {
'Accept' => '*/*',
'Accept-Encoding' => 'gzip',
Expand All @@ -115,7 +115,7 @@
end

it 'returns the splits - with till param' do
stub_request(:get, 'https://sdk.split.io/api/splitChanges?since=-1&till=123123')
stub_request(:get, 'https://sdk.split.io/api/splitChanges?s=1.1&since=-1&till=123123')
.with(headers: {
'Accept' => '*/*',
'Accept-Encoding' => 'gzip',
Expand All @@ -135,7 +135,7 @@
end

it 'returns the splits - checking headers when cache_control_headers is true' do
stub_request(:get, 'https://sdk.split.io/api/splitChanges?since=-1')
stub_request(:get, 'https://sdk.split.io/api/splitChanges?s=1.1&since=-1')
.with(headers: {
'Accept' => '*/*',
'Accept-Encoding' => 'gzip',
Expand All @@ -156,7 +156,7 @@
end

it 'throws exception if request to get splits from API returns unexpected status code' do
stub_request(:get, 'https://sdk.split.io/api/splitChanges?since=-1')
stub_request(:get, 'https://sdk.split.io/api/splitChanges?s=1.1&since=-1')
.to_return(status: 404)

expect { splits_api.since(-1) }.to raise_error(
Expand All @@ -166,7 +166,7 @@
end

it 'throws exception if request to get splits from API fails' do
stub_request(:get, 'https://sdk.split.io/api/splitChanges?since=-1')
stub_request(:get, 'https://sdk.split.io/api/splitChanges?s=1.1&since=-1')
.to_raise(StandardError)

expect { splits_api.since(-1) }.to raise_error(
Expand All @@ -175,7 +175,7 @@
end

it 'throws exception if request to get splits from API times out' do
stub_request(:get, 'https://sdk.split.io/api/splitChanges?since=-1')
stub_request(:get, 'https://sdk.split.io/api/splitChanges?s=1.1&since=-1')
.to_timeout

expect { splits_api.since(-1) }.to raise_error(
Expand Down
Loading

0 comments on commit 0f5ac2f

Please sign in to comment.