splitclient-rb 8.1.3.pre.rc3 → 8.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8c6c7ac46f657ee17dc914ad0772842765a7a7467433fdb220aafe296cd8d34b
4
- data.tar.gz: 20a2d0aa34e77924e879eb83af1c9a402cde5c885e2c03fea2942f1221102413
3
+ metadata.gz: cb1d386fbacf462f6fb540e13b07037fef8bfeab4fcbbda8e1197f63cf64e101
4
+ data.tar.gz: 758c3e6e1cd5d8a6488d283d5eac29fce2942d0b14eb2757b3825a19bbae86f9
5
5
  SHA512:
6
- metadata.gz: d4a4df1e037d2f6a7dcce6fa3630ee944bce3dba3f0d5d18f0993c444fbb1642368fd12432ed6bcd2c964f9be44537132f8fd531a9af1c7a6f3fcbb79b0bfd9d
7
- data.tar.gz: fd4e5b82086e468404cf3cf5b49d9b9b4befa938bf874f7b74a51f704781e270189e1abc9b3d1243b13225a294e60560877c03d175c33e7098cb4c6ce8c016ec
6
+ metadata.gz: 9ad6c553a9af8afe5f2c91db3160d6043d7fd3e2f7c7c2e935c061dc0e49bfae59c5ddb47853c416d67ee692bd0c21c1e0d6c1b88dc51d713ead0a64f0c3c7c9
7
+ data.tar.gz: d4564ffdac1484039e244469b9c845a4def9d817a3a70ab05d1e9b5df78d274a864c2e2c98bb4cc952127b121656ad5522cfa6c6e583fca4422a26953593d157
@@ -0,0 +1 @@
1
+ * @splitio/sdk
@@ -27,7 +27,7 @@ jobs:
27
27
  matrix:
28
28
  version:
29
29
  - '2.5.0'
30
- - '3.1.1'
30
+ - '3.2.2'
31
31
 
32
32
  steps:
33
33
  - name: Checkout code
@@ -56,7 +56,7 @@ jobs:
56
56
  run: echo "VERSION=$(cat lib/splitclient-rb/version.rb | grep VERSION | awk -F "'" '{print $2}')" >> $GITHUB_ENV
57
57
 
58
58
  - name: SonarQube Scan (Push)
59
- if: matrix.version == '3.1.1' && github.event_name == 'push'
59
+ if: matrix.version == '3.2.2' && github.event_name == 'push'
60
60
  uses: SonarSource/sonarcloud-github-action@v1.9
61
61
  env:
62
62
  SONAR_TOKEN: ${{ secrets.SONARQUBE_TOKEN }}
@@ -68,7 +68,7 @@ jobs:
68
68
  -Dsonar.projectVersion=${{ env.VERSION }}
69
69
 
70
70
  - name: SonarQube Scan (Pull Request)
71
- if: matrix.version == '3.1.1' && github.event_name == 'pull_request'
71
+ if: matrix.version == '3.2.2' && github.event_name == 'pull_request'
72
72
  uses: SonarSource/sonarcloud-github-action@v1.9
73
73
  env:
74
74
  SONAR_TOKEN: ${{ secrets.SONARQUBE_TOKEN }}
data/CHANGES.txt CHANGED
@@ -1,5 +1,8 @@
1
1
  CHANGES
2
2
 
3
+ 8.2.0 (Jul 18, 2023)
4
+ - Improved streaming architecture implementation to apply feature flag updates from the notification received which is now enhanced, improving efficiency and reliability of the whole update system.
5
+
3
6
  8.1.2 (May 15, 2023)
4
7
  - Updated terminology on the SDKs codebase to be more aligned with current standard without causing a breaking change. The core change is the term split for feature flag on things like logs and IntelliSense comments.
5
8
 
@@ -46,21 +46,11 @@ module SplitIoClient
46
46
 
47
47
  parsed_splits[:segment_names] =
48
48
  parsed_splits[:splits].each_with_object(Set.new) do |split, splits|
49
- splits << segment_names(split)
49
+ splits << Helpers::Util.segment_names_by_feature_flag(split)
50
50
  end.flatten
51
51
 
52
52
  parsed_splits
53
53
  end
54
-
55
- def segment_names(split)
56
- split[:conditions].each_with_object(Set.new) do |condition, names|
57
- condition[:matcherGroup][:matchers].each do |matcher|
58
- next if matcher[:userDefinedSegmentMatcherData].nil?
59
-
60
- names << matcher[:userDefinedSegmentMatcherData][:segmentName]
61
- end
62
- end
63
- end
64
54
  end
65
55
  end
66
56
  end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SplitIoClient
4
+ module Helpers
5
+ class Util
6
+ def self.segment_names_by_feature_flag(feature_flag)
7
+ feature_flag[:conditions].each_with_object(Set.new) do |condition, names|
8
+ condition[:matcherGroup][:matchers].each do |matcher|
9
+ next if matcher[:userDefinedSegmentMatcherData].nil?
10
+
11
+ names << matcher[:userDefinedSegmentMatcherData][:segmentName]
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -184,7 +184,7 @@ module SplitIoClient
184
184
 
185
185
  def build_streaming_components
186
186
  @push_status_queue = Queue.new
187
- splits_worker = SSE::Workers::SplitsWorker.new(@synchronizer, @config, @splits_repository)
187
+ splits_worker = SSE::Workers::SplitsWorker.new(@synchronizer, @config, @splits_repository, @runtime_producer, @segment_fetcher)
188
188
  segments_worker = SSE::Workers::SegmentsWorker.new(@synchronizer, @config, @segments_repository)
189
189
  notification_manager_keeper = SSE::NotificationManagerKeeper.new(@config, @runtime_producer, @push_status_queue)
190
190
  notification_processor = SSE::NotificationProcessor.new(@config, splits_worker, segments_worker)
@@ -4,12 +4,14 @@ module SplitIoClient
4
4
  module SSE
5
5
  module Workers
6
6
  class SplitsWorker
7
- def initialize(synchronizer, config, feature_flags_repository)
7
+ def initialize(synchronizer, config, feature_flags_repository, telemetry_runtime_producer, segment_fetcher)
8
8
  @synchronizer = synchronizer
9
9
  @config = config
10
10
  @feature_flags_repository = feature_flags_repository
11
11
  @queue = Queue.new
12
12
  @running = Concurrent::AtomicBoolean.new(false)
13
+ @telemetry_runtime_producer = telemetry_runtime_producer
14
+ @segment_fetcher = segment_fetcher
13
15
  end
14
16
 
15
17
  def start
@@ -29,7 +31,7 @@ module SplitIoClient
29
31
  end
30
32
 
31
33
  @running.make_false
32
- SplitIoClient::Helpers::ThreadHelper.stop(:split_update_worker, @config)
34
+ Helpers::ThreadHelper.stop(:split_update_worker, @config)
33
35
  end
34
36
 
35
37
  def add_to_queue(notification)
@@ -39,38 +41,47 @@ module SplitIoClient
39
41
 
40
42
  private
41
43
 
42
- def return_split_from_json(notification)
43
- JSON.parse(
44
- SplitIoClient::Helpers::DecryptionHelper.get_encoded_definition(
45
- notification.data['c'],
46
- notification.data['d']
47
- ),
48
- symbolize_names: true
49
- )
44
+ def perform_thread
45
+ @config.threads[:split_update_worker] = Thread.new do
46
+ @config.logger.debug('starting feature_flags_worker ...') if @config.debug_enabled
47
+ perform
48
+ end
50
49
  end
51
50
 
52
- def check_update(notification)
53
- @feature_flags_repository.get_change_number == notification.data['pcn'] && !notification.data['d'].nil?
51
+ def perform
52
+ while (notification = @queue.pop)
53
+ @config.logger.debug("feature_flags_worker change_number dequeue #{notification.data['changeNumber']}")
54
+ case notification.data['type']
55
+ when SSE::EventSource::EventTypes::SPLIT_UPDATE
56
+ success = update_feature_flag(notification)
57
+ @synchronizer.fetch_splits(notification.data['changeNumber']) unless success
58
+ when SSE::EventSource::EventTypes::SPLIT_KILL
59
+ kill_feature_flag(notification)
60
+ end
61
+ end
54
62
  end
55
63
 
56
64
  def update_feature_flag(notification)
57
- return if @feature_flags_repository.get_change_number.to_i > notification.data['changeNumber']
65
+ return true if @feature_flags_repository.get_change_number.to_i >= notification.data['changeNumber']
66
+ return false unless !notification.data['d'].nil? && @feature_flags_repository.get_change_number == notification.data['pcn']
58
67
 
59
- if check_update(notification)
60
- begin
61
- new_split = return_split_from_json(notification)
62
- if SplitIoClient::Engine::Models::Split.archived?(new_split)
63
- @feature_flags_repository.remove_split(new_split)
64
- else
65
- @feature_flags_repository.add_split(new_split)
66
- end
67
- @feature_flags_repository.set_change_number(notification.data['changeNumber'])
68
- return
69
- rescue StandardError => e
70
- @config.logger.debug("Failed to update Split: #{e.inspect}") if @config.debug_enabled
71
- end
68
+ new_split = return_split_from_json(notification)
69
+ if Engine::Models::Split.archived?(new_split)
70
+ @feature_flags_repository.remove_split(new_split)
71
+ else
72
+ @feature_flags_repository.add_split(new_split)
73
+
74
+ fetch_segments_if_not_exists(new_split)
72
75
  end
73
- @synchronizer.fetch_splits(notification.data['changeNumber'])
76
+
77
+ @feature_flags_repository.set_change_number(notification.data['changeNumber'])
78
+ @telemetry_runtime_producer.record_updates_from_sse(Telemetry::Domain::Constants::SPLITS)
79
+
80
+ true
81
+ rescue StandardError => e
82
+ @config.logger.debug("Failed to update Split: #{e.inspect}") if @config.debug_enabled
83
+
84
+ false
74
85
  end
75
86
 
76
87
  def kill_feature_flag(notification)
@@ -85,23 +96,18 @@ module SplitIoClient
85
96
  @synchronizer.fetch_splits(notification.data['changeNumber'])
86
97
  end
87
98
 
88
- def perform
89
- while (notification = @queue.pop)
90
- @config.logger.debug("feature_flags_worker change_number dequeue #{notification.data['changeNumber']}")
91
- case notification.data['type']
92
- when SSE::EventSource::EventTypes::SPLIT_UPDATE
93
- update_feature_flag(notification)
94
- when SSE::EventSource::EventTypes::SPLIT_KILL
95
- kill_feature_flag(notification)
96
- end
97
- end
99
+ def return_split_from_json(notification)
100
+ split_json = Helpers::DecryptionHelper.get_encoded_definition(notification.data['c'], notification.data['d'])
101
+
102
+ JSON.parse(split_json, symbolize_names: true)
98
103
  end
99
104
 
100
- def perform_thread
101
- @config.threads[:split_update_worker] = Thread.new do
102
- @config.logger.debug('starting feature_flags_worker ...') if @config.debug_enabled
103
- perform
104
- end
105
+ def fetch_segments_if_not_exists(feature_flag)
106
+ segment_names = Helpers::Util.segment_names_by_feature_flag(feature_flag)
107
+ return if segment_names.nil?
108
+
109
+ @feature_flags_repository.set_segment_names(segment_names)
110
+ @segment_fetcher.fetch_segments_if_not_exists(segment_names)
105
111
  end
106
112
  end
107
113
  end
@@ -36,6 +36,8 @@ module SplitIoClient
36
36
  TREATMENT_WITH_CONFIG = 'treatmentWithConfig'
37
37
  TREATMENTS_WITH_CONFIG = 'treatmentsWithConfig'
38
38
  TRACK = 'track'
39
+
40
+ SPLITS = 'splits'
39
41
  end
40
42
  end
41
43
  end
@@ -22,11 +22,14 @@ module SplitIoClient
22
22
  # ls: lastSynchronization, ml: clientMethodLatencies, me: clientMethodExceptions, he: httpErros, hl: httpLatencies,
23
23
  # tr: tokenRefreshes, ar: authRejections, iq: impressionsQueued, ide: impressionsDeduped, idr: impressionsDropped,
24
24
  # spc: splitsCount, sec: segmentCount, skc: segmentKeyCount, sl: sessionLengthMs, eq: eventsQueued, ed: eventsDropped,
25
- # se: streamingEvents, t: tags
26
- Usage = Struct.new(:ls, :ml, :me, :he, :hl, :tr, :ar, :iq, :ide, :idr, :spc, :sec, :skc, :sl, :eq, :ed, :se, :t)
25
+ # se: streamingEvents, t: tags, ufs: updates from sse
26
+ Usage = Struct.new(:ls, :ml, :me, :he, :hl, :tr, :ar, :iq, :ide, :idr, :spc, :sec, :skc, :sl, :eq, :ed, :se, :t, :ufs)
27
27
 
28
28
  # t: treatment, ts: treatments, tc: treatmentWithConfig, tcs: treatmentsWithConfig, tr: track
29
29
  ClientMethodLatencies = Struct.new(:t, :ts, :tc, :tcs, :tr)
30
30
  ClientMethodExceptions = Struct.new(:t, :ts, :tc, :tcs, :tr)
31
+
32
+ # sp: splits
33
+ UpdatesFromSSE = Struct.new(:sp)
31
34
  end
32
35
  end
@@ -94,6 +94,13 @@ module SplitIoClient
94
94
  @adapter.session_length.value
95
95
  end
96
96
 
97
+ def pop_updates_from_sse
98
+ splits = @adapter.updates_from_sse[Domain::Constants::SPLITS]
99
+ @adapter.updates_from_sse[Domain::Constants::SPLITS] = 0
100
+
101
+ UpdatesFromSSE.new(splits)
102
+ end
103
+
97
104
  private
98
105
 
99
106
  def find_last_synchronization(type)
@@ -76,6 +76,12 @@ module SplitIoClient
76
76
  rescue StandardError => e
77
77
  @config.log_found_exception(__method__.to_s, e)
78
78
  end
79
+
80
+ def record_updates_from_sse(event)
81
+ @adapter.updates_from_sse[event] += 1
82
+ rescue StandardError => e
83
+ @config.log_found_exception(__method__.to_s, e)
84
+ end
79
85
  end
80
86
  end
81
87
  end
@@ -34,7 +34,8 @@ module SplitIoClient
34
34
  @telemetry_runtime_consumer.events_stats(Domain::Constants::EVENTS_QUEUED),
35
35
  @telemetry_runtime_consumer.events_stats(Domain::Constants::EVENTS_DROPPED),
36
36
  @telemetry_runtime_consumer.pop_streaming_events,
37
- @telemetry_runtime_consumer.pop_tags)
37
+ @telemetry_runtime_consumer.pop_tags,
38
+ @telemetry_runtime_consumer.pop_updates_from_sse)
38
39
 
39
40
  @telemetry_api.record_stats(format_stats(usage))
40
41
  rescue StandardError => e
@@ -163,7 +164,8 @@ module SplitIoClient
163
164
  eQ: usage.eq,
164
165
  eD: usage.ed,
165
166
  sE: usage.se,
166
- t: usage.t
167
+ t: usage.t,
168
+ ufs: usage.ufs.to_h
167
169
  }
168
170
  end
169
171
 
@@ -14,7 +14,8 @@ module SplitIoClient
14
14
  :pop_auth_rejections,
15
15
  :pop_token_refreshes,
16
16
  :pop_streaming_events,
17
- :session_length
17
+ :session_length,
18
+ :pop_updates_from_sse
18
19
 
19
20
  def initialize(config)
20
21
  @runtime = SplitIoClient::Telemetry::MemoryRuntimeConsumer.new(config)
@@ -14,7 +14,8 @@ module SplitIoClient
14
14
  :record_auth_rejections,
15
15
  :record_token_refreshes,
16
16
  :record_streaming_event,
17
- :record_session_length
17
+ :record_session_length,
18
+ :record_updates_from_sse
18
19
 
19
20
  def initialize(config)
20
21
  @runtime = SplitIoClient::Telemetry::MemoryRuntimeProducer.new(config)
@@ -16,7 +16,8 @@ module SplitIoClient
16
16
  :auth_rejections,
17
17
  :token_refreshes,
18
18
  :streaming_events,
19
- :session_length
19
+ :session_length,
20
+ :updates_from_sse
20
21
 
21
22
  def initialize
22
23
  init_latencies
@@ -32,6 +33,7 @@ module SplitIoClient
32
33
  init_streaming_events
33
34
  init_session_length
34
35
  init_tags
36
+ init_updates_from_sse
35
37
  end
36
38
 
37
39
  def init_latencies
@@ -133,6 +135,12 @@ module SplitIoClient
133
135
  def init_session_length
134
136
  @session_length = Concurrent::AtomicFixnum.new(0)
135
137
  end
138
+
139
+ def init_updates_from_sse
140
+ @updates_from_sse = Concurrent::Hash.new
141
+
142
+ @updates_from_sse[Domain::Constants::SPLITS] = 0
143
+ end
136
144
  end
137
145
  end
138
146
  end
@@ -1,3 +1,3 @@
1
1
  module SplitIoClient
2
- VERSION = '8.1.3.pre.rc3'
2
+ VERSION = '8.2.0'
3
3
  end
@@ -42,6 +42,7 @@ require 'splitclient-rb/clients/split_client'
42
42
  require 'splitclient-rb/managers/split_manager'
43
43
  require 'splitclient-rb/helpers/thread_helper'
44
44
  require 'splitclient-rb/helpers/decryption_helper'
45
+ require 'splitclient-rb/helpers/util'
45
46
  require 'splitclient-rb/split_factory'
46
47
  require 'splitclient-rb/split_factory_builder'
47
48
  require 'splitclient-rb/split_config'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: splitclient-rb
3
3
  version: !ruby/object:Gem::Version
4
- version: 8.1.3.pre.rc3
4
+ version: 8.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Split Software
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-06-28 00:00:00.000000000 Z
11
+ date: 2023-07-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: allocation_stats
@@ -410,6 +410,7 @@ extensions:
410
410
  - ext/murmurhash/extconf.rb
411
411
  extra_rdoc_files: []
412
412
  files:
413
+ - ".github/CODEOWNERS"
413
414
  - ".github/pull_request_template.md"
414
415
  - ".github/workflows/ci.yml"
415
416
  - ".github/workflows/update-license-year.yml"
@@ -519,6 +520,7 @@ files:
519
520
  - lib/splitclient-rb/exceptions.rb
520
521
  - lib/splitclient-rb/helpers/decryption_helper.rb
521
522
  - lib/splitclient-rb/helpers/thread_helper.rb
523
+ - lib/splitclient-rb/helpers/util.rb
522
524
  - lib/splitclient-rb/managers/split_manager.rb
523
525
  - lib/splitclient-rb/split_config.rb
524
526
  - lib/splitclient-rb/split_factory.rb
@@ -577,9 +579,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
577
579
  version: 2.5.0
578
580
  required_rubygems_version: !ruby/object:Gem::Requirement
579
581
  requirements:
580
- - - ">"
582
+ - - ">="
581
583
  - !ruby/object:Gem::Version
582
- version: 1.3.1
584
+ version: '0'
583
585
  requirements: []
584
586
  rubygems_version: 3.2.3
585
587
  signing_key: