splitclient-rb 7.0.3.pre.rc6-java → 7.0.4.pre.rc1-java

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
  SHA1:
3
- metadata.gz: fdd2c89f5ded7d31b8f923c1a4f425c16c4f1868
4
- data.tar.gz: 584a0ac3f6146d6ebc714e4f7d9522c755ee1ad7
3
+ metadata.gz: 011bc30b94b1b3d235bf7c2d549fbe0f3e9d4399
4
+ data.tar.gz: 7673857e19e18b0967a29f7594b60b101139d818
5
5
  SHA512:
6
- metadata.gz: 484c3b699e78bd9317d6c495df29767c1b68bad4966d7e801febc49c99d3a4a0ae88c47339f109dada8a4de27557f472c949360f923c31f3346b4e3ebea78e79
7
- data.tar.gz: 3d983ce1750d405445e49efb47c4fedc4234f719d5deae7f9e175c7f765a9397785614c55507340236930b5a5c722034741ffe15df651b041654544eccf5696c
6
+ metadata.gz: 91ebecabb11b4555f8e469ecacfb5959e19cf9811a1504f8f2bd60c482531346064abf022b91919c374bb612da824d125a50c585201e774f48141b8575236778
7
+ data.tar.gz: ddfcdf53cc0d4ff4965578a01a600a444d514598c07afaad3d67001b5da88dc36564653229d88e2a356277c51211ab2fdb5d182e653e754c68589c790b976194
@@ -1,11 +1,19 @@
1
1
  Documentation:
2
2
  Enabled: false
3
3
 
4
+ Metrics/AbcSize:
5
+ Max: 25
6
+
4
7
  Metrics/MethodLength:
5
- Max: 15
8
+ Max: 20
9
+
10
+ Metrics/ClassLength:
11
+ Max: 120
6
12
 
7
13
  Metrics/LineLength:
8
14
  Max: 121
15
+ Exclude:
16
+ - spec/sse/**/*
9
17
 
10
18
  Metrics/BlockLength:
11
19
  Exclude:
@@ -1,4 +1,4 @@
1
- 7.0.3 (Dec 6, 2019)
1
+ 7.0.3 (Jan 20, 2020)
2
2
  - Added integration tests.
3
3
  - Fixed impressions labels.
4
4
 
@@ -40,7 +40,7 @@
40
40
  define configurations for your treatments and also whitelisted keys. Read more in our docs!
41
41
 
42
42
  6.2.0 (Mar 7th, 2019)
43
- - Reworked SplitClient#destroy to ensure events, impressions and metrics are sent to Split backend when called
43
+ - Reworked SplitClient#destroy to ensure events, impressions and metrics are sent to Split backend when called.
44
44
  - Ensured destroy is called when keyboard interrupts are sent to the application
45
45
  - Changed SDK blocker (and block_until_ready) to have no effect in consumer mode
46
46
  - Added support for applications tied to Faraday < 0.13 and net-http-persistent 3 using a patched Faraday adapter
data/LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright 2018 Split Software, Co.
1
+ Copyright © 2020 Split Software, Inc.
2
2
 
3
3
  Licensed under the Apache License, Version 2.0 (the "License");
4
4
  you may not use this file except in compliance with the License.
@@ -9,6 +9,8 @@ require 'splitclient-rb/cache/adapters/memory_adapters/queue_adapter'
9
9
  require 'splitclient-rb/cache/adapters/cache_adapter'
10
10
  require 'splitclient-rb/cache/adapters/memory_adapter'
11
11
  require 'splitclient-rb/cache/adapters/redis_adapter'
12
+ require 'splitclient-rb/cache/fetchers/segment_fetcher'
13
+ require 'splitclient-rb/cache/fetchers/split_fetcher'
12
14
  require 'splitclient-rb/cache/repositories/repository'
13
15
  require 'splitclient-rb/cache/repositories/segments_repository'
14
16
  require 'splitclient-rb/cache/repositories/splits_repository'
@@ -29,8 +31,6 @@ require 'splitclient-rb/cache/senders/localhost_repo_cleaner'
29
31
  require 'splitclient-rb/cache/stores/store_utils'
30
32
  require 'splitclient-rb/cache/stores/localhost_split_builder'
31
33
  require 'splitclient-rb/cache/stores/sdk_blocker'
32
- require 'splitclient-rb/cache/stores/segment_store'
33
- require 'splitclient-rb/cache/stores/split_store'
34
34
  require 'splitclient-rb/cache/stores/localhost_split_store'
35
35
 
36
36
  require 'splitclient-rb/clients/split_client'
@@ -88,6 +88,15 @@ require 'splitclient-rb/utilitites'
88
88
  # redis metrics fixer
89
89
  require 'splitclient-rb/redis_metrics_fixer'
90
90
 
91
+ # SSE
92
+ require 'splitclient-rb/sse/event_source/client'
93
+ require 'splitclient-rb/sse/event_source/event_types'
94
+ require 'splitclient-rb/sse/event_source/status'
95
+ require 'splitclient-rb/sse/workers/control_worker'
96
+ require 'splitclient-rb/sse/workers/segments_worker'
97
+ require 'splitclient-rb/sse/workers/splits_worker'
98
+ require 'splitclient-rb/sse/sse_handler'
99
+
91
100
  # C extension
92
101
  require 'murmurhash/murmurhash_mri'
93
102
 
@@ -1,7 +1,7 @@
1
1
  module SplitIoClient
2
2
  module Cache
3
- module Stores
4
- class SegmentStore
3
+ module Fetchers
4
+ class SegmentFetcher
5
5
  attr_reader :segments_repository
6
6
 
7
7
  def initialize(segments_repository, api_key, metrics, config, sdk_blocker = nil)
@@ -14,7 +14,7 @@ module SplitIoClient
14
14
 
15
15
  def call
16
16
  if ENV['SPLITCLIENT_ENV'] == 'test'
17
- store_segments
17
+ fetch_segments
18
18
  else
19
19
  segments_thread
20
20
 
@@ -26,16 +26,30 @@ module SplitIoClient
26
26
  end
27
27
  end
28
28
 
29
+ def fetch_segment(name)
30
+ segments_api.fetch_segments_by_names([name])
31
+ rescue StandardError => error
32
+ @config.log_found_exception(__method__.to_s, error)
33
+ end
34
+
35
+ def fetch_segments
36
+ segments_api.fetch_segments_by_names(@segments_repository.used_segment_names)
37
+
38
+ @sdk_blocker.segments_ready!
39
+ rescue StandardError => error
40
+ @config.log_found_exception(__method__.to_s, error)
41
+ end
42
+
29
43
  private
30
44
 
31
45
  def segments_thread
32
- @config.threads[:segment_store] = Thread.new do
46
+ @config.threads[:segment_fetcher] = Thread.new do
33
47
  @config.logger.info('Starting segments fetcher service')
34
48
 
35
49
  loop do
36
50
  next unless @sdk_blocker.splits_repository.ready?
37
51
 
38
- store_segments
52
+ fetch_segments
39
53
  @config.logger.debug("Segment names: #{@segments_repository.used_segment_names.to_a}") if @config.debug_enabled
40
54
 
41
55
  sleep_for = StoreUtils.random_interval(@config.segments_refresh_rate)
@@ -43,15 +57,7 @@ module SplitIoClient
43
57
  sleep(sleep_for)
44
58
  end
45
59
  end
46
- end
47
-
48
- def store_segments
49
- segments_api.store_segments_by_names(@segments_repository.used_segment_names)
50
-
51
- @sdk_blocker.segments_ready!
52
- rescue StandardError => error
53
- @config.log_found_exception(__method__.to_s, error)
54
- end
60
+ end
55
61
 
56
62
  def segments_api
57
63
  @segments_api ||= SplitIoClient::Api::Segments.new(@api_key, @metrics, @segments_repository, @config)
@@ -1,7 +1,7 @@
1
1
  module SplitIoClient
2
2
  module Cache
3
- module Stores
4
- class SplitStore
3
+ module Fetchers
4
+ class SplitFetcher
5
5
  attr_reader :splits_repository
6
6
 
7
7
  def initialize(splits_repository, api_key, metrics, config, sdk_blocker = nil)
@@ -14,7 +14,7 @@ module SplitIoClient
14
14
 
15
15
  def call
16
16
  if ENV['SPLITCLIENT_ENV'] == 'test'
17
- store_splits
17
+ fetch_splits
18
18
  else
19
19
  splits_thread
20
20
 
@@ -26,20 +26,7 @@ module SplitIoClient
26
26
  end
27
27
  end
28
28
 
29
- private
30
-
31
- def splits_thread
32
- @config.threads[:split_store] = Thread.new do
33
- @config.logger.info('Starting splits fetcher service')
34
- loop do
35
- store_splits
36
-
37
- sleep(StoreUtils.random_interval(@config.features_refresh_rate))
38
- end
39
- end
40
- end
41
-
42
- def store_splits
29
+ def fetch_splits
43
30
  data = splits_since(@splits_repository.get_change_number)
44
31
 
45
32
  data[:splits] && data[:splits].each do |split|
@@ -57,6 +44,19 @@ module SplitIoClient
57
44
  @config.log_found_exception(__method__.to_s, error)
58
45
  end
59
46
 
47
+ private
48
+
49
+ def splits_thread
50
+ @config.threads[:split_fetcher] = Thread.new do
51
+ @config.logger.info('Starting splits fetcher service')
52
+ loop do
53
+ fetch_splits
54
+
55
+ sleep(StoreUtils.random_interval(@config.features_refresh_rate))
56
+ end
57
+ end
58
+ end
59
+
60
60
  def splits_since(since)
61
61
  splits_api.since(since)
62
62
  end
@@ -83,8 +83,6 @@ module SplitIoClient
83
83
  @splits_repository.add_split(split)
84
84
  end
85
85
 
86
- private
87
-
88
86
  def splits_api
89
87
  @splits_api ||= SplitIoClient::Api::Splits.new(@api_key, @metrics, @config)
90
88
  end
@@ -128,6 +128,18 @@ module SplitIoClient
128
128
  @adapter.clear(namespace_key)
129
129
  end
130
130
 
131
+ def kill(change_number, split_name, default_treatment)
132
+ split = get_split(split_name)
133
+
134
+ return if split.nil?
135
+
136
+ split[:label] = Engine::Models::Label::KILLED
137
+ split[:defaultTreatment] = default_treatment
138
+ split[:changeNumber] = change_number
139
+
140
+ @adapter.set_string(namespace_key(".split.#{split_name}"), split.to_json)
141
+ end
142
+
131
143
  private
132
144
 
133
145
  def increase_tt_name_count(tt_name)
@@ -9,7 +9,7 @@ module SplitIoClient
9
9
  # @param api_key [String] the API key for your split account
10
10
  #
11
11
  # @return [SplitIoClient] split.io client instance
12
- def initialize(api_key, adapter = nil, splits_repository, segments_repository, impressions_repository, metrics_repository, events_repository, sdk_blocker, config)
12
+ def initialize(api_key, adapter = nil, splits_repository, segments_repository, impressions_repository, metrics_repository, events_repository, sdk_blocker, config, sse_handler)
13
13
  @api_key = api_key
14
14
  @splits_repository = splits_repository
15
15
  @segments_repository = segments_repository
@@ -20,6 +20,7 @@ module SplitIoClient
20
20
  @destroyed = false
21
21
  @config = config
22
22
  @adapter = adapter
23
+ @sse_handler = sse_handler
23
24
  end
24
25
 
25
26
  def get_treatment(
@@ -61,6 +62,8 @@ module SplitIoClient
61
62
  thread.join
62
63
  end
63
64
 
65
+ @sse_handler.sse_client.close if @config.push_notification_enabled
66
+
64
67
  @config.threads.values.each { |thread| Thread.kill(thread) }
65
68
 
66
69
  @splits_repository.clear
@@ -13,7 +13,7 @@ module SplitIoClient
13
13
  @segments_repository = segments_repository
14
14
  end
15
15
 
16
- def store_segments_by_names(names)
16
+ def fetch_segments_by_names(names)
17
17
  start = Time.now
18
18
 
19
19
  return if names.nil? || names.empty?
@@ -1,6 +1,7 @@
1
1
  require 'json'
2
2
  require 'thread'
3
3
 
4
+ include SplitIoClient::Cache::Fetchers
4
5
  include SplitIoClient::Cache::Stores
5
6
  include SplitIoClient::Cache::Senders
6
7
 
@@ -11,7 +12,7 @@ module SplitIoClient
11
12
  # also, uses safe threads to execute fetches and post give the time execution values from the config
12
13
  #
13
14
  class SplitAdapter < NoMethodError
14
- attr_reader :splits_repository, :segments_repository, :impressions_repository, :metrics
15
+ attr_reader :splits_repository, :segments_repository, :impressions_repository, :metrics, :split_fetcher, :segment_fetcher
15
16
 
16
17
  #
17
18
  # Creates a new split api adapter instance that consumes split api endpoints
@@ -50,8 +51,8 @@ module SplitIoClient
50
51
  end
51
52
 
52
53
  def start_standalone_components
53
- split_store
54
- segment_store
54
+ split_fetch
55
+ segment_fetch
55
56
  metrics_sender
56
57
  impressions_sender
57
58
  events_sender
@@ -73,13 +74,15 @@ module SplitIoClient
73
74
  end
74
75
 
75
76
  # Starts thread which loops constantly and stores splits in the splits_repository of choice
76
- def split_store
77
- SplitStore.new(@splits_repository, @api_key, @metrics, @config, @sdk_blocker).call
77
+ def split_fetch
78
+ @split_fetcher = SplitFetcher.new(@splits_repository, @api_key, @metrics, @config, @sdk_blocker)
79
+ @split_fetcher.fetch_splits
78
80
  end
79
81
 
80
82
  # Starts thread which loops constantly and stores segments in the segments_repository of choice
81
- def segment_store
82
- SegmentStore.new(@segments_repository, @api_key, @metrics, @config, @sdk_blocker).call
83
+ def segment_fetch
84
+ @segment_fetcher = SegmentFetcher.new(@segments_repository, @api_key, @metrics, @config, @sdk_blocker)
85
+ @segment_fetcher.fetch_segments
83
86
  end
84
87
 
85
88
  # Starts thread which loops constantly and sends impressions to the Split API
@@ -102,6 +102,8 @@ module SplitIoClient
102
102
  @split_validator = SplitIoClient::Validators.new(self)
103
103
  @localhost_mode = opts[:localhost_mode]
104
104
 
105
+ @push_notification_enabled = opts[:push_notification_enabled].nil? ? true : false
106
+
105
107
  startup_log
106
108
  end
107
109
 
@@ -172,7 +174,6 @@ module SplitIoClient
172
174
  # @return [SplitLogger] The configured logger
173
175
  attr_accessor :split_logger
174
176
 
175
-
176
177
  #
177
178
  # The split validator. The client library uses the split validator
178
179
  # to validate inputs accross the sdk
@@ -255,6 +256,8 @@ module SplitIoClient
255
256
 
256
257
  attr_accessor :ip_addresses_enabled
257
258
 
259
+ attr_accessor :push_notification_enabled
260
+
258
261
  #
259
262
  # The default split client configuration
260
263
  #
@@ -36,7 +36,9 @@ module SplitIoClient
36
36
 
37
37
  @adapter = start!
38
38
 
39
- @client = SplitClient.new(@api_key, @adapter, @splits_repository, @segments_repository, @impressions_repository, @metrics_repository, @events_repository, @sdk_blocker, @config)
39
+ start_sse!
40
+
41
+ @client = SplitClient.new(@api_key, @adapter, @splits_repository, @segments_repository, @impressions_repository, @metrics_repository, @events_repository, @sdk_blocker, @config, @sse_handler)
40
42
  @manager = SplitManager.new(@splits_repository, @sdk_blocker, @config)
41
43
 
42
44
  validate_api_key
@@ -115,5 +117,16 @@ module SplitIoClient
115
117
  @config.valid_mode = false
116
118
  end
117
119
  end
120
+
121
+ def start_sse!
122
+ if @config.push_notification_enabled
123
+ @splits_worker = SSE::Workers::SplitsWorker.new(@adapter, @config, @splits_repository)
124
+ @segments_worker = SSE::Workers::SegmentsWorker.new(@adapter, @config, @segments_repository)
125
+ @control_worker = SSE::Workers::ControlWorker.new(@adapter, @config)
126
+
127
+ options = { channels: 'mauro-c', key: 'fake_key', url_host: 'fake-url' }
128
+ @sse_handler = SSE::SSEHandler.new(@config, options, @splits_worker, @segments_worker, @control_worker)
129
+ end
130
+ end
118
131
  end
119
132
  end
@@ -0,0 +1,162 @@
1
+ # frozen_string_literal: false
2
+
3
+ require 'concurrent/atomics'
4
+ require 'socketry'
5
+ require 'uri'
6
+
7
+ module SplitIoClient
8
+ module SSE
9
+ module EventSource
10
+ class Client
11
+ DEFAULT_READ_TIMEOUT = 200
12
+ KEEP_ALIVE_RESPONSE = "c\r\n:keepalive\n\n\r\n".freeze
13
+
14
+ def initialize(url, config, read_timeout: DEFAULT_READ_TIMEOUT)
15
+ @uri = URI(url)
16
+ @config = config
17
+ @read_timeout = read_timeout
18
+ @connected = Concurrent::AtomicBoolean.new(false)
19
+ @socket = nil
20
+
21
+ @on = { event: ->(_) {}, error: ->(_) {} }
22
+
23
+ yield self if block_given?
24
+
25
+ connect_thread
26
+
27
+ connect_passenger_forked if defined?(PhusionPassenger)
28
+ end
29
+
30
+ def on_event(&action)
31
+ @on[:event] = action
32
+ end
33
+
34
+ def on_error(&action)
35
+ @on[:error] = action
36
+ end
37
+
38
+ def close
39
+ @connected.make_false
40
+ @socket&.close
41
+ @socket = nil
42
+ end
43
+
44
+ def status
45
+ return Status::CONNECTED if @connected.value
46
+
47
+ Status::DISCONNECTED
48
+ end
49
+
50
+ private
51
+
52
+ def connect_thread
53
+ @config.threads[:connect_stream] = Thread.new do
54
+ connect_stream
55
+ end
56
+ end
57
+
58
+ def connect_passenger_forked
59
+ PhusionPassenger.on_event(:starting_worker_process) { |forked| connect_thread if forked }
60
+ end
61
+
62
+ def connect_stream
63
+ @config.logger.info("Connecting to #{@uri.host}...")
64
+
65
+ begin
66
+ @socket = socket_connect
67
+
68
+ @socket.write(build_request(@uri))
69
+ @connected.make_true
70
+ rescue StandardError => e
71
+ dispatch_error(e.inspect)
72
+ end
73
+
74
+ while @connected.value
75
+ begin
76
+ partial_data = @socket.readpartial(2048, timeout: @read_timeout)
77
+ rescue Socketry::TimeoutError
78
+ @config.logger.error("Socket read time out in #{@read_timeout}")
79
+ @connected.make_false
80
+ connect_stream
81
+ end
82
+
83
+ proccess_data(partial_data) unless partial_data == KEEP_ALIVE_RESPONSE
84
+ end
85
+ end
86
+
87
+ def socket_connect
88
+ return Socketry::SSL::Socket.connect(@uri.host, @uri.port) if @uri.scheme.casecmp('https').zero?
89
+
90
+ Socketry::TCP::Socket.connect(@uri.host, @uri.port)
91
+ end
92
+
93
+ def proccess_data(partial_data)
94
+ unless partial_data.nil?
95
+ @config.logger.debug("Event partial data: #{partial_data}")
96
+ buffer = read_partial_data(partial_data)
97
+ event = parse_event(buffer)
98
+
99
+ dispatch_event(event)
100
+ end
101
+ rescue StandardError => e
102
+ dispatch_error(e.inspect)
103
+ end
104
+
105
+ def build_request(uri)
106
+ req = "GET #{uri.request_uri} HTTP/1.1\r\n"
107
+ req << "Host: #{uri.host}\r\n"
108
+ req << "Accept: text/event-stream\r\n"
109
+ req << "Cache-Control: no-cache\r\n"
110
+ req << "\r\n"
111
+ @config.logger.debug("Request info: #{req}")
112
+ req
113
+ end
114
+
115
+ def read_partial_data(data)
116
+ buffer = ''
117
+ buffer << data
118
+ buffer.chomp!
119
+ buffer.split("\n")
120
+ end
121
+
122
+ def parse_event(buffer)
123
+ event_type = nil
124
+ parsed_data = nil
125
+ client_id = nil
126
+
127
+ buffer.each do |d|
128
+ splited_data = d.split(':')
129
+
130
+ case splited_data[0]
131
+ when 'event'
132
+ event_type = splited_data[1].strip
133
+ when 'data'
134
+ event_data = JSON.parse(d.sub('data: ', ''))
135
+ client_id = event_data['clientId']&.strip
136
+ parsed_data = JSON.parse(event_data['data'])
137
+ end
138
+ end
139
+
140
+ return StreamData.new(event_type, client_id, parsed_data) unless event_type.nil? || parsed_data.nil?
141
+
142
+ raise 'Invalid event format.'
143
+ rescue StandardError => e
144
+ dispatch_error(e.inspect)
145
+ nil
146
+ end
147
+
148
+ def dispatch_event(event)
149
+ @config.logger.debug("Dispatching event: #{event}") unless event.nil?
150
+ @on[:event].call(event) unless event.nil?
151
+ end
152
+
153
+ def dispatch_error(error)
154
+ @config.logger.debug("Dispatching error: #{error}")
155
+ @on[:error].call(error)
156
+ end
157
+ end
158
+
159
+ StreamData = Struct.new(:event_type, :client_id, :data)
160
+ end
161
+ end
162
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SplitIoClient
4
+ module SSE
5
+ module EventSource
6
+ class EventTypes
7
+ SPLIT_UPDATE = 'SPLIT_UPDATE'
8
+ SPLIT_KILL = 'SPLIT_KILL'
9
+ SEGMENT_UPDATE = 'SEGMENT_UPDATE'
10
+ CONTROL = 'CONTROL'
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SplitIoClient
4
+ module SSE
5
+ module EventSource
6
+ class Status
7
+ CONNECTING = 'Connecting'
8
+ CONNECTED = 'Connected'
9
+ DISCONNECTED = 'Disconnected'
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,83 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SplitIoClient
4
+ module SSE
5
+ class SSEHandler
6
+ attr_reader :sse_client
7
+
8
+ def initialize(config, options, splits_worker, segments_worker, control_worker)
9
+ @config = config
10
+ @options = options
11
+ @splits_worker = splits_worker
12
+ @segments_worker = segments_worker
13
+ @control_worker = control_worker
14
+
15
+ @sse_client = start_sse_client
16
+ end
17
+
18
+ private
19
+
20
+ def start_sse_client
21
+ url = "#{@options[:url_host]}/event-stream?channels=#{@options[:channels]}&v=1.1&key=#{@options[:key]}"
22
+
23
+ sse_client = SSE::EventSource::Client.new(url, @config) do |client|
24
+ client.on_event do |event|
25
+ process_event(event)
26
+ end
27
+
28
+ client.on_error do |error|
29
+ process_error(error)
30
+ end
31
+ end
32
+
33
+ sse_client
34
+ end
35
+
36
+ def process_event(event)
37
+ case event.data['type']
38
+ when SSE::EventSource::EventTypes::SPLIT_UPDATE
39
+ split_update_notification(event)
40
+ when SSE::EventSource::EventTypes::SPLIT_KILL
41
+ split_kill_notification(event)
42
+ when SSE::EventSource::EventTypes::SEGMENT_UPDATE
43
+ segment_update_notification(event)
44
+ when SSE::EventSource::EventTypes::CONTROL
45
+ control_notification(event)
46
+ else
47
+ @config.logger.error("Incorrect event type: #{event}")
48
+ end
49
+ end
50
+
51
+ def process_error(error)
52
+ @config.logger.error("SSE::EventSource::Client error: #{error}")
53
+ end
54
+
55
+ def split_update_notification(event)
56
+ @config.logger.debug("SPLIT UPDATE notification received: #{event}")
57
+ @splits_worker.add_to_queue(event.data['changeNumber'])
58
+ end
59
+
60
+ def split_kill_notification(event)
61
+ @config.logger.debug("SPLIT KILL notification received: #{event}")
62
+
63
+ change_number = event.data['changeNumber']
64
+ default_treatment = event.data['defaultTreatment']
65
+ split_name = event.data['splitName']
66
+
67
+ @splits_worker.kill_split(change_number, split_name, default_treatment)
68
+ end
69
+
70
+ def segment_update_notification(event)
71
+ @config.logger.debug("SEGMENT UPDATE notification received: #{event}")
72
+ change_number = event.data['changeNumber']
73
+ segment_name = event.data['segmentName']
74
+
75
+ @segments_worker.add_to_queue(change_number, segment_name)
76
+ end
77
+
78
+ def control_notification(event)
79
+ @config.logger.debug("CONTROL notification received: #{event}")
80
+ end
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SplitIoClient
4
+ module SSE
5
+ module Workers
6
+ class ControlWorker
7
+ def initialize(adapter, config)
8
+ @adapter = adapter
9
+ @config = config
10
+
11
+ perform_thread
12
+
13
+ perform_passenger_forked if defined?(PhusionPassenger)
14
+ end
15
+
16
+ private
17
+
18
+ def perform
19
+ # TODO: IMPLEMENT THIS METHOD
20
+ end
21
+
22
+ def perform_thread
23
+ @config.threads[:segment_update_worker] = Thread.new do
24
+ perform
25
+ end
26
+ end
27
+
28
+ def perform_passenger_forked
29
+ PhusionPassenger.on_event(:starting_worker_process) { |forked| perform_thread if forked }
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SplitIoClient
4
+ module SSE
5
+ module Workers
6
+ class SegmentsWorker
7
+ def initialize(adapter, config, segments_repository)
8
+ @adapter = adapter
9
+ @config = config
10
+ @segments_repository = segments_repository
11
+ @queue = Queue.new
12
+
13
+ perform_thread
14
+
15
+ perform_passenger_forked if defined?(PhusionPassenger)
16
+ end
17
+
18
+ def add_to_queue(change_number, segment_name)
19
+ item = { change_number: change_number, segment_name: segment_name }
20
+ @queue.push(item)
21
+ end
22
+
23
+ private
24
+
25
+ def perform
26
+ while (item = @queue.pop)
27
+ segment_name = item[:segment_name]
28
+ change_number = item[:change_number]
29
+ since = @segments_repository.get_change_number(segment_name)
30
+
31
+ @adapter.segment_fetcher.fetch_segment(segment_name) unless since >= change_number
32
+ end
33
+ end
34
+
35
+ def perform_thread
36
+ @config.threads[:segment_update_worker] = Thread.new do
37
+ perform
38
+ end
39
+ end
40
+
41
+ def perform_passenger_forked
42
+ PhusionPassenger.on_event(:starting_worker_process) { |forked| perform_thread if forked }
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SplitIoClient
4
+ module SSE
5
+ module Workers
6
+ class SplitsWorker
7
+ def initialize(adapter, config, splits_repository)
8
+ @adapter = adapter
9
+ @config = config
10
+ @splits_repository = splits_repository
11
+ @queue = Queue.new
12
+
13
+ perform_thread
14
+
15
+ perform_passenger_forked if defined?(PhusionPassenger)
16
+ end
17
+
18
+ def add_to_queue(change_number)
19
+ @queue.push(change_number)
20
+ end
21
+
22
+ def kill_split(change_number, split_name, default_treatment)
23
+ @splits_repository.kill(change_number, split_name, default_treatment)
24
+ add_to_queue(change_number)
25
+ end
26
+
27
+ private
28
+
29
+ def perform
30
+ while (change_number = @queue.pop)
31
+ since = @splits_repository.get_change_number
32
+ @adapter.split_fetcher.fetch_splits unless since >= change_number
33
+ end
34
+ end
35
+
36
+ def perform_thread
37
+ @config.threads[:split_update_worker] = Thread.new do
38
+ perform
39
+ end
40
+ end
41
+
42
+ def perform_passenger_forked
43
+ PhusionPassenger.on_event(:starting_worker_process) { |forked| perform_thread if forked }
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
@@ -1,3 +1,3 @@
1
1
  module SplitIoClient
2
- VERSION = '7.0.3.pre.rc6'
2
+ VERSION = '7.0.4.pre.rc1'
3
3
  end
@@ -54,5 +54,6 @@ Gem::Specification.new do |spec|
54
54
  spec.add_runtime_dependency 'lru_redux'
55
55
  spec.add_runtime_dependency 'net-http-persistent', '>= 2.9'
56
56
  spec.add_runtime_dependency 'redis', '>= 3.2'
57
+ spec.add_runtime_dependency 'socketry', '~> 0.5.1'
57
58
  spec.add_runtime_dependency 'thread_safe', '>= 0.3'
58
59
  end
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: 7.0.3.pre.rc6
4
+ version: 7.0.4.pre.rc1
5
5
  platform: java
6
6
  authors:
7
7
  - Split Software
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-01-16 00:00:00.000000000 Z
11
+ date: 2020-03-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  requirement: !ruby/object:Gem::Requirement
@@ -262,6 +262,20 @@ dependencies:
262
262
  - - ">="
263
263
  - !ruby/object:Gem::Version
264
264
  version: '3.2'
265
+ - !ruby/object:Gem::Dependency
266
+ requirement: !ruby/object:Gem::Requirement
267
+ requirements:
268
+ - - "~>"
269
+ - !ruby/object:Gem::Version
270
+ version: 0.5.1
271
+ name: socketry
272
+ prerelease: false
273
+ type: :runtime
274
+ version_requirements: !ruby/object:Gem::Requirement
275
+ requirements:
276
+ - - "~>"
277
+ - !ruby/object:Gem::Version
278
+ version: 0.5.1
265
279
  - !ruby/object:Gem::Dependency
266
280
  requirement: !ruby/object:Gem::Requirement
267
281
  requirements:
@@ -307,6 +321,8 @@ files:
307
321
  - lib/splitclient-rb/cache/adapters/memory_adapters/map_adapter.rb
308
322
  - lib/splitclient-rb/cache/adapters/memory_adapters/queue_adapter.rb
309
323
  - lib/splitclient-rb/cache/adapters/redis_adapter.rb
324
+ - lib/splitclient-rb/cache/fetchers/segment_fetcher.rb
325
+ - lib/splitclient-rb/cache/fetchers/split_fetcher.rb
310
326
  - lib/splitclient-rb/cache/repositories/events/memory_repository.rb
311
327
  - lib/splitclient-rb/cache/repositories/events/redis_repository.rb
312
328
  - lib/splitclient-rb/cache/repositories/events_repository.rb
@@ -328,8 +344,6 @@ files:
328
344
  - lib/splitclient-rb/cache/stores/localhost_split_builder.rb
329
345
  - lib/splitclient-rb/cache/stores/localhost_split_store.rb
330
346
  - lib/splitclient-rb/cache/stores/sdk_blocker.rb
331
- - lib/splitclient-rb/cache/stores/segment_store.rb
332
- - lib/splitclient-rb/cache/stores/split_store.rb
333
347
  - lib/splitclient-rb/cache/stores/store_utils.rb
334
348
  - lib/splitclient-rb/clients/split_client.rb
335
349
  - lib/splitclient-rb/engine/api/client.rb
@@ -380,6 +394,13 @@ files:
380
394
  - lib/splitclient-rb/split_factory_builder.rb
381
395
  - lib/splitclient-rb/split_factory_registry.rb
382
396
  - lib/splitclient-rb/split_logger.rb
397
+ - lib/splitclient-rb/sse/event_source/client.rb
398
+ - lib/splitclient-rb/sse/event_source/event_types.rb
399
+ - lib/splitclient-rb/sse/event_source/status.rb
400
+ - lib/splitclient-rb/sse/sse_handler.rb
401
+ - lib/splitclient-rb/sse/workers/control_worker.rb
402
+ - lib/splitclient-rb/sse/workers/segments_worker.rb
403
+ - lib/splitclient-rb/sse/workers/splits_worker.rb
383
404
  - lib/splitclient-rb/utilitites.rb
384
405
  - lib/splitclient-rb/validators.rb
385
406
  - lib/splitclient-rb/version.rb