bunny 1.3.0 → 2.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/.github/ISSUE_TEMPLATE.md +18 -0
- data/.gitignore +7 -1
- data/.rspec +1 -3
- data/.travis.yml +21 -14
- data/CONTRIBUTING.md +132 -0
- data/ChangeLog.md +887 -1
- data/Gemfile +13 -13
- data/LICENSE +1 -1
- data/README.md +46 -60
- data/Rakefile +54 -0
- data/bunny.gemspec +5 -11
- data/docker-compose.yml +28 -0
- data/docker/Dockerfile +24 -0
- data/docker/apt/preferences.d/erlang +3 -0
- data/docker/apt/sources.list.d/bintray.rabbitmq.list +2 -0
- data/docker/docker-entrypoint.sh +26 -0
- data/docker/rabbitmq.conf +29 -0
- data/examples/connection/automatic_recovery_with_basic_get.rb +1 -1
- data/examples/connection/automatic_recovery_with_client_named_queues.rb +1 -1
- data/examples/connection/automatic_recovery_with_multiple_consumers.rb +1 -1
- data/examples/connection/automatic_recovery_with_republishing.rb +1 -1
- data/examples/connection/automatic_recovery_with_server_named_queues.rb +1 -1
- data/examples/connection/channel_level_exception.rb +1 -9
- data/examples/connection/disabled_automatic_recovery.rb +1 -1
- data/examples/connection/heartbeat.rb +1 -1
- data/examples/consumers/high_and_low_priority.rb +1 -1
- data/examples/guides/extensions/alternate_exchange.rb +2 -0
- data/examples/guides/extensions/basic_nack.rb +1 -1
- data/examples/guides/extensions/dead_letter_exchange.rb +1 -1
- data/examples/guides/getting_started/hello_world.rb +2 -0
- data/examples/guides/getting_started/weathr.rb +2 -0
- data/examples/guides/queues/one_off_consumer.rb +2 -0
- data/examples/guides/queues/redeliveries.rb +4 -2
- data/lib/bunny.rb +8 -4
- data/lib/bunny/channel.rb +268 -153
- data/lib/bunny/channel_id_allocator.rb +6 -4
- data/lib/bunny/concurrent/continuation_queue.rb +34 -13
- data/lib/bunny/consumer_work_pool.rb +34 -6
- data/lib/bunny/cruby/socket.rb +48 -21
- data/lib/bunny/cruby/ssl_socket.rb +65 -4
- data/lib/bunny/exceptions.rb +25 -4
- data/lib/bunny/exchange.rb +24 -28
- data/lib/bunny/get_response.rb +1 -1
- data/lib/bunny/heartbeat_sender.rb +3 -2
- data/lib/bunny/jruby/socket.rb +23 -6
- data/lib/bunny/jruby/ssl_socket.rb +5 -0
- data/lib/bunny/queue.rb +31 -22
- data/lib/bunny/reader_loop.rb +31 -18
- data/lib/bunny/session.rb +448 -159
- data/lib/bunny/test_kit.rb +14 -0
- data/lib/bunny/timeout.rb +1 -12
- data/lib/bunny/transport.rb +205 -98
- data/lib/bunny/version.rb +1 -1
- data/repl +1 -1
- data/spec/config/enabled_plugins +1 -0
- data/spec/config/rabbitmq.conf +13 -0
- data/spec/higher_level_api/integration/basic_ack_spec.rb +175 -16
- data/spec/higher_level_api/integration/basic_cancel_spec.rb +77 -11
- data/spec/higher_level_api/integration/basic_consume_spec.rb +60 -55
- data/spec/higher_level_api/integration/basic_consume_with_objects_spec.rb +6 -6
- data/spec/higher_level_api/integration/basic_get_spec.rb +31 -7
- data/spec/higher_level_api/integration/basic_nack_spec.rb +22 -19
- data/spec/higher_level_api/integration/basic_publish_spec.rb +11 -100
- data/spec/higher_level_api/integration/basic_qos_spec.rb +32 -4
- data/spec/higher_level_api/integration/basic_reject_spec.rb +94 -16
- data/spec/higher_level_api/integration/basic_return_spec.rb +4 -4
- data/spec/higher_level_api/integration/channel_close_spec.rb +51 -10
- data/spec/higher_level_api/integration/channel_open_spec.rb +12 -12
- data/spec/higher_level_api/integration/connection_recovery_spec.rb +424 -221
- data/spec/higher_level_api/integration/connection_spec.rb +300 -126
- data/spec/higher_level_api/integration/connection_stop_spec.rb +31 -19
- data/spec/higher_level_api/integration/consumer_cancellation_notification_spec.rb +17 -17
- data/spec/higher_level_api/integration/dead_lettering_spec.rb +34 -11
- data/spec/higher_level_api/integration/exchange_bind_spec.rb +5 -5
- data/spec/higher_level_api/integration/exchange_declare_spec.rb +32 -31
- data/spec/higher_level_api/integration/exchange_delete_spec.rb +12 -12
- data/spec/higher_level_api/integration/exchange_unbind_spec.rb +5 -5
- data/spec/higher_level_api/integration/exclusive_queue_spec.rb +5 -5
- data/spec/higher_level_api/integration/heartbeat_spec.rb +26 -8
- data/spec/higher_level_api/integration/message_properties_access_spec.rb +49 -49
- data/spec/higher_level_api/integration/predeclared_exchanges_spec.rb +2 -2
- data/spec/higher_level_api/integration/publisher_confirms_spec.rb +156 -42
- data/spec/higher_level_api/integration/publishing_edge_cases_spec.rb +19 -19
- data/spec/higher_level_api/integration/queue_bind_spec.rb +23 -23
- data/spec/higher_level_api/integration/queue_declare_spec.rb +129 -34
- data/spec/higher_level_api/integration/queue_delete_spec.rb +2 -2
- data/spec/higher_level_api/integration/queue_purge_spec.rb +5 -5
- data/spec/higher_level_api/integration/queue_unbind_spec.rb +6 -6
- data/spec/higher_level_api/integration/read_only_consumer_spec.rb +9 -9
- data/spec/higher_level_api/integration/sender_selected_distribution_spec.rb +10 -10
- data/spec/higher_level_api/integration/tls_connection_spec.rb +224 -89
- data/spec/higher_level_api/integration/toxiproxy_spec.rb +76 -0
- data/spec/higher_level_api/integration/tx_commit_spec.rb +1 -1
- data/spec/higher_level_api/integration/tx_rollback_spec.rb +1 -1
- data/spec/higher_level_api/integration/with_channel_spec.rb +2 -2
- data/spec/issues/issue100_spec.rb +11 -11
- data/spec/issues/issue141_spec.rb +13 -14
- data/spec/issues/issue202_spec.rb +1 -1
- data/spec/issues/issue224_spec.rb +40 -0
- data/spec/issues/issue465_spec.rb +32 -0
- data/spec/issues/issue549_spec.rb +30 -0
- data/spec/issues/issue78_spec.rb +21 -24
- data/spec/issues/issue83_spec.rb +5 -6
- data/spec/issues/issue97_spec.rb +44 -45
- data/spec/lower_level_api/integration/basic_cancel_spec.rb +15 -16
- data/spec/lower_level_api/integration/basic_consume_spec.rb +20 -21
- data/spec/spec_helper.rb +8 -26
- data/spec/stress/channel_close_stress_spec.rb +64 -0
- data/spec/stress/channel_open_stress_spec.rb +15 -9
- data/spec/stress/channel_open_stress_with_single_threaded_connection_spec.rb +7 -7
- data/spec/stress/concurrent_consumers_stress_spec.rb +18 -16
- data/spec/stress/concurrent_publishers_stress_spec.rb +16 -19
- data/spec/stress/connection_open_close_spec.rb +9 -9
- data/spec/stress/merry_go_round_spec.rb +105 -0
- data/spec/tls/client_key.pem +49 -25
- data/spec/tls/generate-server-cert.sh +8 -0
- data/spec/tls/server-openssl.cnf +10 -0
- data/spec/tls/server.csr +16 -0
- data/spec/tls/server_key.pem +49 -25
- data/spec/toxiproxy_helper.rb +28 -0
- data/spec/unit/bunny_spec.rb +5 -5
- data/spec/unit/concurrent/atomic_fixnum_spec.rb +6 -6
- data/spec/unit/concurrent/condition_spec.rb +8 -8
- data/spec/unit/concurrent/linked_continuation_queue_spec.rb +2 -2
- data/spec/unit/concurrent/synchronized_sorted_set_spec.rb +16 -16
- data/spec/unit/exchange_recovery_spec.rb +39 -0
- data/spec/unit/version_delivery_tag_spec.rb +3 -3
- metadata +65 -47
- data/.ruby-version +0 -1
- data/lib/bunny/compatibility.rb +0 -24
- data/lib/bunny/system_timer.rb +0 -20
- data/spec/compatibility/queue_declare_spec.rb +0 -44
- data/spec/compatibility/queue_declare_with_default_channel_spec.rb +0 -33
- data/spec/higher_level_api/integration/basic_recover_spec.rb +0 -18
- data/spec/higher_level_api/integration/confirm_select_spec.rb +0 -19
- data/spec/higher_level_api/integration/consistent_hash_exchange_spec.rb +0 -50
- data/spec/higher_level_api/integration/merry_go_round_spec.rb +0 -85
- data/spec/stress/long_running_consumer_spec.rb +0 -83
- data/spec/tls/cacert.pem +0 -18
- data/spec/tls/client_cert.pem +0 -18
- data/spec/tls/server_cert.pem +0 -18
- data/spec/unit/system_timer_spec.rb +0 -10
@@ -17,7 +17,9 @@ module Bunny
|
|
17
17
|
#
|
18
18
|
|
19
19
|
# @param [Integer] max_channel Max allowed channel id
|
20
|
-
def initialize(max_channel = ((1 <<
|
20
|
+
def initialize(max_channel = ((1 << 11) - 1))
|
21
|
+
# channel 0 has special meaning in the protocol, so start
|
22
|
+
# allocator at 1
|
21
23
|
@allocator = AMQ::IntAllocator.new(1, max_channel)
|
22
24
|
@mutex = Monitor.new
|
23
25
|
end
|
@@ -25,7 +27,7 @@ module Bunny
|
|
25
27
|
|
26
28
|
# Returns next available channel id. This method is thread safe.
|
27
29
|
#
|
28
|
-
# @return [
|
30
|
+
# @return [Integer]
|
29
31
|
# @api public
|
30
32
|
# @see ChannelManager#release_channel_id
|
31
33
|
# @see ChannelManager#reset_channel_id_allocator
|
@@ -37,7 +39,7 @@ module Bunny
|
|
37
39
|
|
38
40
|
# Releases previously allocated channel id. This method is thread safe.
|
39
41
|
#
|
40
|
-
# @param [
|
42
|
+
# @param [Integer] i Channel id to release
|
41
43
|
# @api public
|
42
44
|
# @see ChannelManager#next_channel_id
|
43
45
|
# @see ChannelManager#reset_channel_id_allocator
|
@@ -51,7 +53,7 @@ module Bunny
|
|
51
53
|
# Returns true if given channel id has been previously allocated and not yet released.
|
52
54
|
# This method is thread safe.
|
53
55
|
#
|
54
|
-
# @param [
|
56
|
+
# @param [Integer] i Channel id to check
|
55
57
|
# @return [Boolean] true if given channel id has been previously allocated and not yet released
|
56
58
|
# @api public
|
57
59
|
# @see ChannelManager#next_channel_id
|
@@ -6,36 +6,57 @@ module Bunny
|
|
6
6
|
#
|
7
7
|
# @private
|
8
8
|
class ContinuationQueue
|
9
|
-
def initialize
|
10
|
-
@q
|
9
|
+
def initialize
|
10
|
+
@q = []
|
11
|
+
@lock = ::Mutex.new
|
12
|
+
@cond = ::ConditionVariable.new
|
11
13
|
end
|
12
14
|
|
13
|
-
def push(
|
14
|
-
@
|
15
|
+
def push(item)
|
16
|
+
@lock.synchronize do
|
17
|
+
@q.push(item)
|
18
|
+
@cond.signal
|
19
|
+
end
|
15
20
|
end
|
16
21
|
alias << push
|
17
22
|
|
18
23
|
def pop
|
19
|
-
|
24
|
+
poll
|
20
25
|
end
|
21
26
|
|
22
27
|
def poll(timeout_in_ms = nil)
|
23
|
-
|
24
|
-
|
25
|
-
|
28
|
+
timeout = timeout_in_ms ? timeout_in_ms / 1000.0 : nil
|
29
|
+
|
30
|
+
@lock.synchronize do
|
31
|
+
timeout_strikes_at = Time.now.utc + (timeout || 0)
|
32
|
+
while @q.empty?
|
33
|
+
wait = if timeout
|
34
|
+
timeout_strikes_at - Time.now.utc
|
35
|
+
else
|
36
|
+
nil
|
37
|
+
end
|
38
|
+
@cond.wait(@lock, wait)
|
39
|
+
raise ::Timeout::Error if wait && Time.now.utc >= timeout_strikes_at
|
26
40
|
end
|
27
|
-
|
28
|
-
|
41
|
+
item = @q.shift
|
42
|
+
item
|
29
43
|
end
|
30
44
|
end
|
31
45
|
|
32
46
|
def clear
|
33
|
-
@
|
47
|
+
@lock.synchronize do
|
48
|
+
@q.clear
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def empty?
|
53
|
+
@q.empty?
|
34
54
|
end
|
35
55
|
|
36
|
-
def
|
37
|
-
@q.
|
56
|
+
def size
|
57
|
+
@q.size
|
38
58
|
end
|
59
|
+
alias length size
|
39
60
|
end
|
40
61
|
end
|
41
62
|
end
|
@@ -15,10 +15,17 @@ module Bunny
|
|
15
15
|
|
16
16
|
attr_reader :threads
|
17
17
|
attr_reader :size
|
18
|
+
attr_reader :abort_on_exception
|
18
19
|
|
19
|
-
def initialize(size = 1)
|
20
|
+
def initialize(size = 1, abort_on_exception = false, shutdown_timeout = 60)
|
20
21
|
@size = size
|
22
|
+
@abort_on_exception = abort_on_exception
|
23
|
+
@shutdown_timeout = shutdown_timeout
|
24
|
+
@shutdown_mutex = ::Mutex.new
|
25
|
+
@shutdown_conditional = ::ConditionVariable.new
|
21
26
|
@queue = ::Queue.new
|
27
|
+
@paused = false
|
28
|
+
@running = false
|
22
29
|
end
|
23
30
|
|
24
31
|
|
@@ -31,6 +38,7 @@ module Bunny
|
|
31
38
|
|
32
39
|
@size.times do
|
33
40
|
t = Thread.new(&method(:run_loop))
|
41
|
+
t.abort_on_exception = true if abort_on_exception
|
34
42
|
@threads << t
|
35
43
|
end
|
36
44
|
|
@@ -41,7 +49,16 @@ module Bunny
|
|
41
49
|
@running
|
42
50
|
end
|
43
51
|
|
44
|
-
def
|
52
|
+
def backlog
|
53
|
+
@queue.length
|
54
|
+
end
|
55
|
+
|
56
|
+
def busy?
|
57
|
+
!@queue.empty?
|
58
|
+
end
|
59
|
+
|
60
|
+
def shutdown(wait_for_workers = false)
|
61
|
+
was_running = running?
|
45
62
|
@running = false
|
46
63
|
|
47
64
|
@size.times do
|
@@ -49,20 +66,26 @@ module Bunny
|
|
49
66
|
throw :terminate
|
50
67
|
end
|
51
68
|
end
|
69
|
+
|
70
|
+
return if !(wait_for_workers && @shutdown_timeout && was_running)
|
71
|
+
|
72
|
+
@shutdown_mutex.synchronize do
|
73
|
+
@shutdown_conditional.wait(@shutdown_mutex, @shutdown_timeout)
|
74
|
+
end
|
52
75
|
end
|
53
76
|
|
54
77
|
def join(timeout = nil)
|
55
|
-
@threads.each { |t| t.join(timeout) }
|
78
|
+
(@threads || []).each { |t| t.join(timeout) }
|
56
79
|
end
|
57
80
|
|
58
81
|
def pause
|
59
82
|
@running = false
|
60
|
-
|
61
|
-
@threads.each { |t| t.stop }
|
83
|
+
@paused = true
|
62
84
|
end
|
63
85
|
|
64
86
|
def resume
|
65
87
|
@running = true
|
88
|
+
@paused = false
|
66
89
|
|
67
90
|
@threads.each { |t| t.run }
|
68
91
|
end
|
@@ -70,7 +93,7 @@ module Bunny
|
|
70
93
|
def kill
|
71
94
|
@running = false
|
72
95
|
|
73
|
-
@threads.each { |t| t.kill }
|
96
|
+
(@threads || []).each { |t| t.kill }
|
74
97
|
end
|
75
98
|
|
76
99
|
protected
|
@@ -78,6 +101,7 @@ module Bunny
|
|
78
101
|
def run_loop
|
79
102
|
catch(:terminate) do
|
80
103
|
loop do
|
104
|
+
Thread.stop if @paused
|
81
105
|
callable = @queue.pop
|
82
106
|
|
83
107
|
begin
|
@@ -89,6 +113,10 @@ module Bunny
|
|
89
113
|
end
|
90
114
|
end
|
91
115
|
end
|
116
|
+
|
117
|
+
@shutdown_mutex.synchronize do
|
118
|
+
@shutdown_conditional.signal unless busy?
|
119
|
+
end
|
92
120
|
end
|
93
121
|
end
|
94
122
|
end
|
data/lib/bunny/cruby/socket.rb
CHANGED
@@ -6,23 +6,40 @@ module Bunny
|
|
6
6
|
#
|
7
7
|
# Heavily inspired by Dalli by Mike Perham.
|
8
8
|
# @private
|
9
|
-
|
9
|
+
module Socket
|
10
10
|
attr_accessor :options
|
11
11
|
|
12
|
-
|
13
|
-
|
14
|
-
|
12
|
+
READ_RETRY_EXCEPTION_CLASSES = if defined?(IO::EAGAINWaitReadable)
|
13
|
+
# Ruby 2.1+
|
14
|
+
[Errno::EAGAIN, Errno::EWOULDBLOCK, IO::WaitReadable,
|
15
|
+
IO::EAGAINWaitReadable, IO::EWOULDBLOCKWaitReadable]
|
16
|
+
else
|
17
|
+
# 2.0
|
18
|
+
[Errno::EAGAIN, Errno::EWOULDBLOCK, IO::WaitReadable]
|
19
|
+
end
|
20
|
+
WRITE_RETRY_EXCEPTION_CLASSES = if defined?(IO::EAGAINWaitWritable)
|
21
|
+
[Errno::EAGAIN, Errno::EWOULDBLOCK, IO::WaitWritable,
|
22
|
+
IO::EAGAINWaitWritable, IO::EWOULDBLOCKWaitWritable]
|
23
|
+
else
|
24
|
+
# 2.0
|
25
|
+
[Errno::EAGAIN, Errno::EWOULDBLOCK, IO::WaitWritable]
|
26
|
+
end
|
15
27
|
|
16
28
|
def self.open(host, port, options = {})
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
29
|
+
socket = ::Socket.tcp(host, port, nil, nil,
|
30
|
+
connect_timeout: options[:connect_timeout])
|
31
|
+
if ::Socket.constants.include?('TCP_NODELAY') || ::Socket.constants.include?(:TCP_NODELAY)
|
32
|
+
socket.setsockopt(::Socket::IPPROTO_TCP, ::Socket::TCP_NODELAY, true)
|
33
|
+
end
|
34
|
+
socket.setsockopt(::Socket::SOL_SOCKET, ::Socket::SO_KEEPALIVE, true) if options.fetch(:keepalive, true)
|
35
|
+
socket.instance_eval do
|
36
|
+
@__bunny_socket_eof_flag__ = false
|
25
37
|
end
|
38
|
+
socket.extend self
|
39
|
+
socket.options = { :host => host, :port => port }.merge(options)
|
40
|
+
socket
|
41
|
+
rescue Errno::ETIMEDOUT
|
42
|
+
raise ClientTimeout
|
26
43
|
end
|
27
44
|
|
28
45
|
# Reads given number of bytes with an optional timeout
|
@@ -62,22 +79,32 @@ module Bunny
|
|
62
79
|
# if this is not appropriate in your case.
|
63
80
|
#
|
64
81
|
# @param [String] data Data to write
|
82
|
+
# @param [Integer] timeout Timeout
|
65
83
|
#
|
66
84
|
# @api public
|
67
|
-
def write_nonblock_fully(data)
|
85
|
+
def write_nonblock_fully(data, timeout = nil)
|
68
86
|
return nil if @__bunny_socket_eof_flag__
|
69
87
|
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
88
|
+
length = data.bytesize
|
89
|
+
total_count = 0
|
90
|
+
count = 0
|
91
|
+
loop do
|
92
|
+
begin
|
93
|
+
count = self.write_nonblock(data)
|
94
|
+
rescue *WRITE_RETRY_EXCEPTION_CLASSES
|
95
|
+
if IO.select([], [self], nil, timeout)
|
96
|
+
retry
|
97
|
+
else
|
98
|
+
raise Timeout::Error, "IO timeout when writing to socket"
|
99
|
+
end
|
74
100
|
end
|
75
|
-
|
76
|
-
|
77
|
-
|
101
|
+
|
102
|
+
total_count += count
|
103
|
+
return total_count if total_count >= length
|
104
|
+
data = data.byteslice(count..-1)
|
78
105
|
end
|
79
106
|
|
80
|
-
data.bytesize
|
81
107
|
end
|
108
|
+
|
82
109
|
end
|
83
110
|
end
|
@@ -8,10 +8,26 @@ module Bunny
|
|
8
8
|
# methods found in Bunny::Socket.
|
9
9
|
class SSLSocket < OpenSSL::SSL::SSLSocket
|
10
10
|
|
11
|
-
|
12
|
-
|
13
|
-
|
11
|
+
READ_RETRY_EXCEPTION_CLASSES = if defined?(IO::EAGAINWaitReadable)
|
12
|
+
# Ruby 2.1+
|
13
|
+
[Errno::EAGAIN, Errno::EWOULDBLOCK, IO::WaitReadable,
|
14
|
+
IO::EAGAINWaitReadable, IO::EWOULDBLOCKWaitReadable]
|
15
|
+
else
|
16
|
+
# 2.0
|
17
|
+
[Errno::EAGAIN, Errno::EWOULDBLOCK, IO::WaitReadable]
|
18
|
+
end
|
19
|
+
WRITE_RETRY_EXCEPTION_CLASSES = if defined?(IO::EAGAINWaitWritable)
|
20
|
+
[Errno::EAGAIN, Errno::EWOULDBLOCK, IO::WaitWritable,
|
21
|
+
IO::EAGAINWaitWritable, IO::EWOULDBLOCKWaitWritable]
|
22
|
+
else
|
23
|
+
# 2.0
|
24
|
+
[Errno::EAGAIN, Errno::EWOULDBLOCK, IO::WaitWritable]
|
25
|
+
end
|
14
26
|
|
27
|
+
def initialize(*args)
|
28
|
+
super
|
29
|
+
@__bunny_socket_eof_flag__ = false
|
30
|
+
end
|
15
31
|
|
16
32
|
# Reads given number of bytes with an optional timeout
|
17
33
|
#
|
@@ -50,8 +66,53 @@ module Bunny
|
|
50
66
|
end
|
51
67
|
value
|
52
68
|
end
|
69
|
+
|
70
|
+
# Writes provided data using IO#write_nonblock, taking care of handling
|
71
|
+
# of exceptions it raises when writing would fail (e.g. due to socket buffer
|
72
|
+
# being full).
|
73
|
+
#
|
74
|
+
# IMPORTANT: this method will mutate (slice) the argument. Pass in duplicates
|
75
|
+
# if this is not appropriate in your case.
|
76
|
+
#
|
77
|
+
# @param [String] data Data to write
|
78
|
+
# @param [Integer] timeout Timeout
|
79
|
+
#
|
80
|
+
# @api public
|
81
|
+
def write_nonblock_fully(data, timeout = nil)
|
82
|
+
return nil if @__bunny_socket_eof_flag__
|
83
|
+
|
84
|
+
length = data.bytesize
|
85
|
+
total_count = 0
|
86
|
+
count = 0
|
87
|
+
loop do
|
88
|
+
begin
|
89
|
+
count = self.write_nonblock(data)
|
90
|
+
rescue OpenSSL::SSL::SSLError => e
|
91
|
+
if e.message == "write would block"
|
92
|
+
if IO.select([], [self], nil, timeout)
|
93
|
+
retry
|
94
|
+
else
|
95
|
+
raise Timeout::Error, "IO timeout when writing to socket"
|
96
|
+
end
|
97
|
+
end
|
98
|
+
raise e
|
99
|
+
rescue *WRITE_RETRY_EXCEPTION_CLASSES
|
100
|
+
if IO.select([], [self], nil, timeout)
|
101
|
+
retry
|
102
|
+
else
|
103
|
+
raise Timeout::Error, "IO timeout when writing to socket"
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
total_count += count
|
108
|
+
return total_count if total_count >= length
|
109
|
+
data = data.byteslice(count..-1)
|
110
|
+
end
|
111
|
+
|
112
|
+
end
|
113
|
+
|
53
114
|
end
|
54
|
-
rescue LoadError
|
115
|
+
rescue LoadError
|
55
116
|
puts "Could not load OpenSSL"
|
56
117
|
end
|
57
118
|
end
|
data/lib/bunny/exceptions.rb
CHANGED
@@ -4,6 +4,12 @@ module Bunny
|
|
4
4
|
class Exception < ::StandardError
|
5
5
|
end
|
6
6
|
|
7
|
+
class HostListDepleted < Exception
|
8
|
+
def initialize
|
9
|
+
super("No more hosts to try in the supplied list of hosts")
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
7
13
|
# Indicates a network failure. If automatic network
|
8
14
|
# recovery mode is enabled, these will be typically handled
|
9
15
|
# by the client itself.
|
@@ -54,20 +60,29 @@ module Bunny
|
|
54
60
|
end
|
55
61
|
end
|
56
62
|
|
57
|
-
|
58
63
|
# Raised when TCP connection to RabbitMQ fails because of an unresolved
|
59
64
|
# hostname, connectivity problem, etc
|
60
65
|
class TCPConnectionFailed < Exception
|
61
66
|
attr_reader :hostname, :port
|
62
67
|
|
63
|
-
def initialize(e, hostname, port)
|
68
|
+
def initialize(e, hostname=nil, port=nil)
|
64
69
|
m = case e
|
65
70
|
when String then
|
66
71
|
e
|
67
|
-
when Exception then
|
72
|
+
when ::Exception then
|
68
73
|
e.message
|
69
74
|
end
|
70
|
-
|
75
|
+
if hostname && port
|
76
|
+
super("Could not establish TCP connection to #{hostname}:#{port}: #{m}")
|
77
|
+
else
|
78
|
+
super(m)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
class TCPConnectionFailedForAllHosts < TCPConnectionFailed
|
84
|
+
def initialize
|
85
|
+
super("Could not establish TCP connection to any of the configured hosts", nil, nil)
|
71
86
|
end
|
72
87
|
end
|
73
88
|
|
@@ -82,6 +97,12 @@ module Bunny
|
|
82
97
|
end
|
83
98
|
end
|
84
99
|
|
100
|
+
class ConnectionAlreadyClosed < Exception
|
101
|
+
def initialize
|
102
|
+
super('Connection has been already closed')
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
85
106
|
class ShutdownSignal < Exception
|
86
107
|
end
|
87
108
|
|