Skip to content

Commit 8a68e43

Browse files
authored
Merge pull request #598 from splitio/FME-10791-fix-timeout
Fme 10791 fix timeout
2 parents e4f1293 + 0d0ccdf commit 8a68e43

3 files changed

Lines changed: 66 additions & 26 deletions

File tree

lib/splitclient-rb/sse/event_source/client.rb

Lines changed: 35 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -86,35 +86,45 @@ def connect_thread(latch)
8686
def connect_stream(latch)
8787
return Constants::PUSH_NONRETRYABLE_ERROR unless socket_write(latch)
8888
while connected? || @first_event.value
89-
begin
90-
partial_data = ""
91-
Timeout::timeout @read_timeout do
89+
if IO.select([@socket], nil, nil, @read_timeout)
90+
begin
9291
partial_data = @socket.readpartial(10_000)
93-
end
94-
read_first_event(partial_data, latch)
95-
96-
raise 'eof exception' if partial_data == :eof
97-
rescue Timeout::Error => e
98-
log_if_debug("SSE read operation timed out!: #{e.inspect}", 3)
99-
return Constants::PUSH_RETRYABLE_ERROR
100-
rescue EOFError
101-
raise 'eof exception'
102-
rescue Errno::EAGAIN => e
103-
log_if_debug("SSE client transient error: #{e.inspect}", 1)
104-
IO.select([tcp_socket])
105-
retry
106-
rescue Errno::EBADF, IOError => e
107-
log_if_debug(e.inspect, 3)
108-
return nil
109-
rescue StandardError => e
110-
return nil if ENV['SPLITCLIENT_ENV'] == 'test'
92+
read_first_event(partial_data, latch)
11193

112-
log_if_debug("Error reading partial data: #{e.inspect}", 3)
94+
raise 'eof exception' if partial_data == :eof
95+
rescue IO::WaitReadable => e
96+
log_if_debug("SSE client transient error: #{e.inspect}", 1)
97+
IO.select([@socket], nil, nil, @read_timeout)
98+
retry
99+
rescue Errno::ETIMEDOUT => e
100+
log_if_debug("SSE read operation timed out!: #{e.inspect}", 3)
101+
return Constants::PUSH_RETRYABLE_ERROR
102+
rescue EOFError => e
103+
log_if_debug("SSE read operation EOF Exception!: #{e.inspect}", 3)
104+
raise 'eof exception'
105+
rescue Errno::EAGAIN => e
106+
log_if_debug("SSE client transient error: #{e.inspect}", 1)
107+
IO.select([@socket], nil, nil, @read_timeout)
108+
retry
109+
rescue Errno::EBADF, IOError => e
110+
log_if_debug("SSE read operation EBADF or IOError: #{e.inspect}", 3)
111+
return nil
112+
rescue StandardError => e
113+
log_if_debug("SSE read operation StandardError: #{e.inspect}", 3)
114+
return nil if ENV['SPLITCLIENT_ENV'] == 'test'
115+
116+
log_if_debug("Error reading partial data: #{e.inspect}", 3)
117+
return Constants::PUSH_RETRYABLE_ERROR
118+
end
119+
else
120+
@config.logger.debug("SSE read operation timed out, no data available.")
113121
return Constants::PUSH_RETRYABLE_ERROR
114122
end
115123

116124
process_data(partial_data)
117125
end
126+
log_if_debug("SSE read operation exited: #{connected?}", 1)
127+
118128
nil
119129
end
120130

@@ -142,6 +152,7 @@ def read_first_event(data, latch)
142152

143153
if response_code == OK_CODE && !error_event
144154
@connected.make_true
155+
@config.logger.debug("SSE client first event Connected is true")
145156
@telemetry_runtime_producer.record_streaming_event(Telemetry::Domain::Constants::SSE_CONNECTION_ESTABLISHED, nil)
146157
push_status(Constants::PUSH_CONNECTED)
147158
end
@@ -166,9 +177,8 @@ def socket_connect
166177
IO.select(nil, [ssl_socket])
167178
retry
168179
end
169-
170180
return ssl_socket
171-
# return ssl_socket.connect
181+
172182
rescue Exception => e
173183
@config.logger.error("socket connect error: #{e.inspect}")
174184
return nil
@@ -179,9 +189,9 @@ def socket_connect
179189
end
180190

181191
def process_data(partial_data)
192+
log_if_debug("Event partial data: #{partial_data}", 1)
182193
return if partial_data.nil? || partial_data == KEEP_ALIVE_RESPONSE
183194

184-
log_if_debug("Event partial data: #{partial_data}", 1)
185195
events = @event_parser.parse(partial_data)
186196
events.each { |event| process_event(event) }
187197
rescue StandardError => e

lib/splitclient-rb/version.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
module SplitIoClient
2-
VERSION = '8.10.0-rc2'
2+
VERSION = '8.10.0-rc5'
33
end

spec/sse/event_source/client_spec.rb

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,36 @@
221221
end
222222
end
223223

224+
it 'client timeout and reconnect' do
225+
stub_request(:get, 'https://sdk.split.io/api/splitChanges?s=1.3&since=-1&rbSince=-1')
226+
.with(headers: { 'Authorization' => 'Bearer client-spec-key' })
227+
.to_return(status: 200, body: '{"ff":{"d":[],"s":-1,"t":5564531221}, "rbs":{"d":[],"s":-1,"t":-1}}')
228+
stub_request(:get, 'https://sdk.split.io/api/splitChanges?s=1.3&since=5564531221&rbSince=-1')
229+
.with(headers: { 'Authorization' => 'Bearer client-spec-key' })
230+
.to_return(status: 200, body: '{"ff":{"d":[],"s":5564531221,"t":5564531221}, "rbs":{"d":[],"s":-1,"t":-1}}')
231+
232+
mock_server do |server|
233+
start_workers
234+
server.setup_response('/') do |_, res|
235+
send_stream_content(res, event_split_update)
236+
end
237+
238+
sse_client = subject.new(config, api_token, telemetry_runtime_producer, event_parser, notification_manager_keeper, notification_processor, push_status_queue, read_timeout: 0.1)
239+
connected = sse_client.start(server.base_uri)
240+
sleep 1
241+
expect(connected).to eq(true)
242+
expect(sse_client.connected?).to eq(true)
243+
expect(push_status_queue.pop(true)).to eq(SplitIoClient::Constants::PUSH_CONNECTED)
244+
sleep 3
245+
expect(log.string).to include 'SSE read operation timed out, no data available'
246+
expect(sse_client.connected?).to eq(true)
247+
sse_client.close
248+
expect(sse_client.connected?).to eq(false)
249+
250+
stop_workers
251+
end
252+
end
253+
224254
it 'first event - when server return 400' do
225255
mock_server do |server|
226256
server.setup_response('/') do |_, res|

0 commit comments

Comments
 (0)