Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Development #534

Closed
wants to merge 71 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
71 commits
Select commit Hold shift + click to select a range
2968a19
added undefined matcher flow
Mar 5, 2024
5cbe5dc
polish
Mar 5, 2024
c770cff
Merge pull request #510 from splitio/undefined-matcher
chillaq Mar 5, 2024
75cc222
added semver class
Mar 26, 2024
21f408b
polish
Mar 26, 2024
6b83afc
added equalto semver matcher
Mar 28, 2024
93d73b0
polish
Mar 28, 2024
45fbd0b
polish
Mar 28, 2024
8aa6bb9
added greater than or equal to semver matcher
Mar 28, 2024
30232f8
added less than or equal semver matcher
Mar 29, 2024
2f95e4b
added semver between matcher
Mar 29, 2024
2749c65
added in list semver matcher
Mar 29, 2024
7fd6f34
polish
Mar 29, 2024
e9677d9
fixed matcher logic
Apr 1, 2024
dc0caa6
fixed matcher logic
Apr 1, 2024
9f1b7d9
semver matchers integrations spec
Apr 1, 2024
8a1d214
Used csv for spec and added builder for semver class
Apr 8, 2024
f12ee2a
added csv files
Apr 8, 2024
acad113
updated using build for semver class
Apr 9, 2024
1e4a238
used build for semver class
Apr 9, 2024
8bf838b
used build for semver class
Apr 9, 2024
cf60f11
used build for semver class
Apr 9, 2024
61b8c9e
fixed condition
Apr 9, 2024
8cc7ff5
Merge pull request #514 from splitio/semver-class
chillaq Apr 10, 2024
f875912
Merge pull request #516 from splitio/semver-equalto-matcher
chillaq Apr 10, 2024
608c259
Merge pull request #517 from splitio/semver-greater-or-equalto-matcher
chillaq Apr 10, 2024
229a9f7
Merge pull request #518 from splitio/semver-less-or-equalto-matcher
chillaq Apr 10, 2024
89826a3
Merge pull request #519 from splitio/semver-between-matcher
chillaq Apr 10, 2024
f76b944
Merge pull request #521 from splitio/semver-integration-spec
chillaq Apr 10, 2024
980c272
added version attribute and used it in compare
Apr 10, 2024
b9e8fd8
updated semver spec
Apr 10, 2024
b1529d2
Fixed compare logic in semver, equalto and inlist matchers.
Apr 10, 2024
a8761d7
Added nil check for all matchers and updated specs
Apr 11, 2024
5a084a8
polish
Apr 11, 2024
a302223
Merge branch 'Feature/Semver' into semver-inlist-matcher
chillaq Apr 11, 2024
7ec5da7
added version length check for compare
Apr 11, 2024
4ecad51
correcting specs and comparisons
Apr 11, 2024
a1cab94
Merge pull request #525 from splitio/semver-inlist-matcher
chillaq Apr 11, 2024
fecd3b1
fixed occupancy publishers
sanzmauro Apr 17, 2024
f0b9c97
update spec
sanzmauro Apr 17, 2024
8ad8992
update notification manager
sanzmauro Apr 17, 2024
d90a18d
implementation
sanzmauro Apr 17, 2024
774ce4c
fixed spec
sanzmauro Apr 18, 2024
6804f26
Merge pull request #527 from splitio/sdks-8260-occupancy
sanzmauro Apr 18, 2024
0113765
Merge branch 'development' into unsupported-matcher
sanzmauro Apr 18, 2024
cecc9f3
Merge pull request #528 from splitio/unsupported-matcher
sanzmauro Apr 18, 2024
b2cfbcd
fixed posting data before shutdown
Apr 22, 2024
4406ef7
removed thwait lib
Apr 23, 2024
be09c7b
polish
Apr 23, 2024
bfaf1d2
polish
Apr 23, 2024
58512ba
added limit for joining thread
Apr 23, 2024
4c9e171
fixed join timeout
Apr 24, 2024
71320e2
Merge pull request #529 from splitio/post-data-destroy
chillaq Apr 24, 2024
a0a6055
added spec query parameter
Apr 24, 2024
796014b
Merge branch 'development' into semver-spec-query
chillaq Apr 24, 2024
fd4eb7d
fix specs
Apr 24, 2024
ab10e30
moved spec constant to nw spec module
Apr 25, 2024
7cb1c31
new spec module
Apr 25, 2024
6eafede
Merge pull request #530 from splitio/semver-spec-query
chillaq Apr 26, 2024
0f5ac2f
Merge branch 'development' into Feature/Semver
chillaq May 1, 2024
db9311a
updated query api order, fixed spec and added error to split logger
May 1, 2024
418e5d7
added debug to split logger
May 1, 2024
b7ecdd1
update debug logging in semver matchers
May 1, 2024
1bc71a5
fixed spec
May 1, 2024
abea9d2
polishing
May 1, 2024
581d6e3
polish
May 1, 2024
50fe596
polish
May 2, 2024
2a54d08
polish and test update
May 2, 2024
91b9266
Merge pull request #532 from splitio/Feature/Semver
chillaq May 2, 2024
9299411
release 8.4.0
May 2, 2024
496265d
Merge pull request #533 from splitio/release-8.4.0
chillaq May 2, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGES.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
CHANGES

8.4.0 (May 3, 2024)
- Fixed issue preventing Impressopns and Events posting if client.destroy is called before the post threads started
- Added support for targeting rules based on semantic versions (https://semver.org/).

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
Expand Down
8 changes: 8 additions & 0 deletions lib/splitclient-rb.rb
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,12 @@
require 'splitclient-rb/engine/matchers/equal_to_boolean_matcher'
require 'splitclient-rb/engine/matchers/equal_to_matcher'
require 'splitclient-rb/engine/matchers/matches_string_matcher'
require 'splitclient-rb/engine/matchers/semver'
require 'splitclient-rb/engine/matchers/equal_to_semver_matcher'
require 'splitclient-rb/engine/matchers/greater_than_or_equal_to_semver_matcher'
require 'splitclient-rb/engine/matchers/less_than_or_equal_to_semver_matcher'
require 'splitclient-rb/engine/matchers/between_semver_matcher'
require 'splitclient-rb/engine/matchers/in_list_semver_matcher'
require 'splitclient-rb/engine/evaluator/splitter'
require 'splitclient-rb/engine/impressions/noop_unique_keys_tracker'
require 'splitclient-rb/engine/impressions/unique_keys_tracker'
Expand All @@ -105,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
42 changes: 42 additions & 0 deletions lib/splitclient-rb/cache/repositories/splits_repository.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,32 @@ module Cache
module Repositories
class SplitsRepository < Repository
attr_reader :adapter
DEFAULT_CONDITIONS_TEMPLATE = [{
conditionType: "ROLLOUT",
matcherGroup: {
combiner: "AND",
matchers: [
{
keySelector: nil,
matcherType: "ALL_KEYS",
negate: false,
userDefinedSegmentMatcherData: nil,
whitelistMatcherData: nil,
unaryNumericMatcherData: nil,
betweenMatcherData: nil,
dependencyMatcherData: nil,
booleanMatcherData: nil,
stringMatcherData: nil
}]
},
partitions: [
{
treatment: "control",
size: 100
}
],
label: "targeting rule type unsupported by sdk"
}]

def initialize(config, flag_sets_repository, flag_set_filter)
super(config)
Expand Down Expand Up @@ -155,6 +181,10 @@ def add_feature_flag(split)
remove_from_flag_sets(existing_split)
end

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
end
if !split[:sets].nil?
for flag_set in split[:sets]
if !@flag_sets.flag_set_exist?(flag_set)
Expand All @@ -170,6 +200,18 @@ def add_feature_flag(split)
@adapter.set_string(namespace_key(".split.#{split[:name]}"), split.to_json)
end

def check_undefined_matcher(split)
for condition in split[:conditions]
for matcher in condition[:matcherGroup][:matchers]
if !SplitIoClient::Condition.instance_methods(false).map(&:to_s).include?("matcher_#{matcher[:matcherType].downcase}")
@config.logger.error("Detected undefined matcher #{matcher[:matcherType].downcase} in feature flag #{split[:name]}")
return true
end
end
end
return false
end

def remove_feature_flag(split)
decrease_tt_name_count(split[:trafficTypeName])
remove_from_flag_sets(split)
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
7 changes: 4 additions & 3 deletions lib/splitclient-rb/engine/api/splits.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,20 @@ 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[:till] = fetch_options[:till] unless fetch_options[:till].nil?
params = { s: SplitIoClient::Spec::FeatureFlags::SPEC_VERSION, since: since }
params[:sets] = @flag_sets_filter.join(",") unless @flag_sets_filter.empty?
params[:till] = fetch_options[:till] unless fetch_options[:till].nil?
@config.logger.debug("Fetching from splitChanges with #{params}: ")
response = get_api("#{@config.base_uri}/splitChanges", @api_key, params, fetch_options[:cache_control_headers])
if response.status == 414
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
33 changes: 33 additions & 0 deletions lib/splitclient-rb/engine/matchers/between_semver_matcher.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# frozen_string_literal: true

module SplitIoClient
class BetweenSemverMatcher < Matcher
MATCHER_TYPE = 'BETWEEN_SEMVER'

attr_reader :attribute

def initialize(attribute, start_value, end_value, logger, validator)
super(logger)
@validator = validator
@attribute = attribute
@semver_start = SplitIoClient::Semver.build(start_value, logger)
@semver_end = SplitIoClient::Semver.build(end_value, logger)
@logger = logger
end

def match?(args)
return false unless verify_semver_arg?(args, 'BetweenSemverMatcher')

value_to_match = SplitIoClient::Semver.build(args[:attributes][@attribute.to_sym], @logger)
if value_to_match.nil? || @semver_start.nil? || @semver_end.nil?
@logger.error('betweenStringMatcherData is required for BETWEEN_SEMVER matcher type')
return false

end
matches = ([0, -1].include?(@semver_start.compare(value_to_match)) &&
[0, 1].include?(@semver_end.compare(value_to_match)))
@logger.debug("[BetweenMatcher] #{value_to_match} matches -> #{matches}")
matches
end
end
end
28 changes: 28 additions & 0 deletions lib/splitclient-rb/engine/matchers/equal_to_semver_matcher.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# frozen_string_literal: true

module SplitIoClient
class EqualToSemverMatcher < Matcher
MATCHER_TYPE = 'EQUAL_TO_SEMVER'

attr_reader :attribute

def initialize(attribute, string_value, logger, validator)
super(logger)
@validator = validator
@attribute = attribute
@semver = SplitIoClient::Semver.build(string_value, logger)
@logger = logger
end

def match?(args)
return false unless verify_semver_arg?(args, 'EqualsToSemverMatcher')

value_to_match = SplitIoClient::Semver.build(args[:attributes][@attribute.to_sym], @logger)
return false unless check_semver_value_to_match(value_to_match, MATCHER_TYPE)

matches = (@semver.version == value_to_match.version)
@logger.debug("[EqualsToSemverMatcher] #{value_to_match} matches -> #{matches}")
matches
end
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# frozen_string_literal: true

module SplitIoClient
class GreaterThanOrEqualToSemverMatcher < Matcher
MATCHER_TYPE = 'GREATER_THAN_OR_EQUAL_TO_SEMVER'

attr_reader :attribute

def initialize(attribute, string_value, logger, validator)
super(logger)
@validator = validator
@attribute = attribute
@semver = SplitIoClient::Semver.build(string_value, logger)
@logger = logger
end

def match?(args)
return false unless verify_semver_arg?(args, 'GreaterThanOrEqualsToSemverMatcher')

value_to_match = SplitIoClient::Semver.build(args[:attributes][@attribute.to_sym], @logger)
return false unless check_semver_value_to_match(value_to_match, MATCHER_TYPE)

matches = [0, 1].include?(value_to_match.compare(@semver))
@logger.debug("[GreaterThanOrEqualsToSemverMatcher] #{value_to_match} matches -> #{matches}")
matches
end
end
end
36 changes: 36 additions & 0 deletions lib/splitclient-rb/engine/matchers/in_list_semver_matcher.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# frozen_string_literal: true

module SplitIoClient
class InListSemverMatcher < Matcher
MATCHER_TYPE = 'IN_LIST_SEMVER'

attr_reader :attribute

def initialize(attribute, list_value, logger, validator)
super(logger)
@validator = validator
@attribute = attribute
@semver_list = []

list_value.map do |item|
version = SplitIoClient::Semver.build(item, logger)
@semver_list << version unless version.nil?
end
@logger = logger
end

def match?(args)
return false if @semver_list.empty? || !verify_semver_arg?(args, 'InListSemverMatcher')

value_to_match = SplitIoClient::Semver.build(args[:attributes][@attribute.to_sym], @logger)
if value_to_match.nil?
@logger.error('whitelistMatcherData is required for IN_LIST_SEMVER matcher type')
return false

end
matches = (@semver_list.map { |item| item.version == value_to_match.version }).any? { |item| item == true }
@logger.debug("[InListSemverMatcher] #{value_to_match} matches -> #{matches}")
matches
end
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# frozen_string_literal: true

module SplitIoClient
class LessThanOrEqualToSemverMatcher < Matcher
MATCHER_TYPE = 'LESS_THAN_OR_EQUAL_TO_SEMVER'

attr_reader :attribute

def initialize(attribute, string_value, logger, validator)
super(logger)
@validator = validator
@attribute = attribute
@semver = SplitIoClient::Semver.build(string_value, logger)
@logger = logger
end

def match?(args)
return false unless verify_semver_arg?(args, 'LessThanOrEqualsToSemverMatcher')

value_to_match = SplitIoClient::Semver.build(args[:attributes][@attribute.to_sym], @logger)
return false unless check_semver_value_to_match(value_to_match, MATCHER_TYPE)

matches = [0, -1].include?(value_to_match.compare(@semver))
@logger.debug("[LessThanOrEqualsToSemverMatcher] #{value_to_match} matches -> #{matches}")
matches
end
end
end
18 changes: 18 additions & 0 deletions lib/splitclient-rb/engine/matchers/matcher.rb
Original file line number Diff line number Diff line change
Expand Up @@ -30,5 +30,23 @@ def equals?(obj)
def string_type?
false
end

private

def verify_semver_arg?(args, matcher_name)
@logger.debug("[#{matcher_name}] evaluating value and attributes.")
return false unless @validator.valid_matcher_arguments(args)

true
end

def check_semver_value_to_match(value_to_match, matcher_spec_name)
if value_to_match.nil? || @semver.nil?
@logger.error("stringMatcherData is required for #{matcher_spec_name} matcher type")
return false

end
true
end
end
end
Loading
Loading