Skip to content

Commit

Permalink
Handle Errno::ECONNRESET and empty buffer reads with celluloid-io.
Browse files Browse the repository at this point in the history
  • Loading branch information
dblock committed Aug 20, 2018
1 parent d239896 commit c7a067d
Show file tree
Hide file tree
Showing 4 changed files with 84 additions and 38 deletions.
2 changes: 1 addition & 1 deletion .rubocop_todo.yml
@@ -1,6 +1,6 @@
# This configuration was generated by
# `rubocop --auto-gen-config`
# on 2018-08-20 07:57:38 -0400 using RuboCop version 0.58.2.
# on 2018-08-20 08:24:54 -0400 using RuboCop version 0.58.2.
# The point is for the user to remove these configuration records
# one by one as the offenses are removed from the code base.
# Note that changes in the inspected code, or installation of new
Expand Down
3 changes: 2 additions & 1 deletion CHANGELOG.md
@@ -1,6 +1,6 @@
### 0.11.2 (Next)

* Your contribution here.
* [#216](https://github.com/slack-ruby/slack-ruby-client/pull/216): Handle `Errno::ECONNRESET` and empty buffer reads with celluloid-io - [@dblock](https://github.com/dblock).
* [#215](https://github.com/slack-ruby/slack-ruby-client/pull/215): Web API `groups_list`, `files_info`, `mpim_list`, `reactions_list` and `stars_list` now support cursor pagination - [@hotwatermorning](https://github.com/hotwatermorning).
* [#215](https://github.com/slack-ruby/slack-ruby-client/pull/215): Added `apps_permissions_users_list` and `apps_permissions_users_request` - [@hotwatermorning](https://github.com/hotwatermorning).
* [#209](https://github.com/slack-ruby/slack-ruby-client/pull/209): Changed `chat_postEphemeral`to check for existence of either `text` or `attachments` - [@peterzhu2118](https://github.com/peterzhu2118).
Expand All @@ -9,6 +9,7 @@
* [#206](https://github.com/slack-ruby/slack-ruby-client/pull/206): Fix 100% cpu usage in async examples - [@felixbuenemann](https://github.com/felixbuenemann).
* [#217](https://github.com/slack-ruby/slack-ruby-client/pull/217): Upgraded RuboCop to 0.58.2 - [@dblock](https://github.com/dblock).
* [#217](https://github.com/slack-ruby/slack-ruby-client/pull/217): No longer tested with Ruby 2.1, added 2.5 - [@dblock](https://github.com/dblock).
* Your contribution here.

### 0.11.1 (1/23/2018)

Expand Down
3 changes: 2 additions & 1 deletion lib/slack/real_time/concurrency/celluloid.rb
Expand Up @@ -34,7 +34,7 @@ def run_loop
@connected = @socket.connect
driver.start
loop { read } if socket
rescue EOFError, Errno::EPIPE => e
rescue EOFError, Errno::ECONNRESET, Errno::EPIPE => e
logger.debug("#{self.class}##{__method__}") { e }
driver.emit(:close, WebSocket::Driver::CloseEvent.new(1001, 'server closed connection')) unless @closing
ensure
Expand All @@ -53,6 +53,7 @@ def close

def read
buffer = socket.readpartial(BLOCK_SIZE)
raise EOFError unless buffer && !buffer.empty?
async.handle_read(buffer)
end

Expand Down
114 changes: 79 additions & 35 deletions spec/slack/real_time/concurrency/celluloid_spec.rb
Expand Up @@ -4,59 +4,103 @@
begin
RSpec.describe Slack::RealTime::Concurrency::Celluloid::Socket do
it_behaves_like 'a realtime socket'
context 'with url' do
let(:url) { 'wss://echo.websocket.org/websocket/xyz' }
let(:logger) { ::Logger.new(STDOUT) }

[EOFError, Errno::EPIPE].each do |err|
context "finishing run_loop with #{err}" do
let(:test_socket) do
Class.new(described_class) do
def read
raise options[:err]
end

let(:url) { 'wss://echo.websocket.org/websocket/xyz' }
let(:logger) { ::Logger.new(STDOUT) }

let(:driver) { WebSocket::Driver::Client }
let(:ws) { double(driver) }
subject { socket }

['', nil].each do |data|
context "finishing run_loop with #{data ? 'empty' : 'nil'} read" do
let(:ssl_socket) do
Class.new(Celluloid::IO::SSLSocket) do
def initialize(data)
@data = data
end

def connect; end

def readpartial(_size)
@data
end
end
end

let(:socket) do
test_socket.new(url, ping: 42, logger: logger, err: err)
let(:test_socket) do
Class.new(described_class) do
def build_socket
options[:ssl_socket].new(options[:data])
end
end
end

let(:driver) { WebSocket::Driver::Client }
let(:ws) { double(driver) }
subject { socket }
let(:socket) do
test_socket.new(url, logger: logger, data: data, ssl_socket: ssl_socket)
end

describe '#connect!' do
pending 'connects'
pending 'pings every 30s'
context 'with a driver' do
before do
socket.instance_variable_set('@driver', ws)
end

context 'with a driver' do
before do
socket.instance_variable_set('@driver', ws)
context 'consumes data' do
it 'runs' do
expect(ws).to receive(:emit)
expect(ws).to receive(:start)
expect(logger).to receive(:debug).with("#{test_socket}#run_loop")
socket.run_loop
end
end
end
end
end

describe '#disconnect!' do
it 'closes and nils the websocket' do
expect(ws).to receive(:close)
socket.disconnect!
end
[EOFError, Errno::ECONNRESET, Errno::EPIPE].each do |err|
context "finishing run_loop with #{err}" do
let(:test_socket) do
Class.new(described_class) do
def read
raise options[:err]
end
end
end

let(:socket) do
test_socket.new(url, logger: logger, err: err)
end

context 'with a driver' do
before do
socket.instance_variable_set('@driver', ws)
end

context 'consumes data' do
it 'runs' do
expect(ws).to receive(:emit)
expect(ws).to receive(:start)
expect(logger).to receive(:debug).with("#{test_socket}#run_loop")
socket.run_loop
end
describe '#disconnect!' do
it 'closes and nils the websocket' do
expect(ws).to receive(:close)
socket.disconnect!
end
end

pending 'send_data'
context 'consumes data' do
it 'runs' do
expect(ws).to receive(:emit)
expect(ws).to receive(:start)
expect(logger).to receive(:debug).with("#{test_socket}#run_loop")
socket.run_loop
end
end
end
end
end

describe '#connect!' do
pending 'connects'
pending 'pings every 30s'
end

pending 'send_data'
end
rescue LoadError
end

0 comments on commit c7a067d

Please sign in to comment.