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.
Files changed (143) hide show
  1. checksums.yaml +5 -5
  2. data/.github/ISSUE_TEMPLATE.md +18 -0
  3. data/.gitignore +7 -1
  4. data/.rspec +1 -3
  5. data/.travis.yml +21 -14
  6. data/CONTRIBUTING.md +132 -0
  7. data/ChangeLog.md +887 -1
  8. data/Gemfile +13 -13
  9. data/LICENSE +1 -1
  10. data/README.md +46 -60
  11. data/Rakefile +54 -0
  12. data/bunny.gemspec +5 -11
  13. data/docker-compose.yml +28 -0
  14. data/docker/Dockerfile +24 -0
  15. data/docker/apt/preferences.d/erlang +3 -0
  16. data/docker/apt/sources.list.d/bintray.rabbitmq.list +2 -0
  17. data/docker/docker-entrypoint.sh +26 -0
  18. data/docker/rabbitmq.conf +29 -0
  19. data/examples/connection/automatic_recovery_with_basic_get.rb +1 -1
  20. data/examples/connection/automatic_recovery_with_client_named_queues.rb +1 -1
  21. data/examples/connection/automatic_recovery_with_multiple_consumers.rb +1 -1
  22. data/examples/connection/automatic_recovery_with_republishing.rb +1 -1
  23. data/examples/connection/automatic_recovery_with_server_named_queues.rb +1 -1
  24. data/examples/connection/channel_level_exception.rb +1 -9
  25. data/examples/connection/disabled_automatic_recovery.rb +1 -1
  26. data/examples/connection/heartbeat.rb +1 -1
  27. data/examples/consumers/high_and_low_priority.rb +1 -1
  28. data/examples/guides/extensions/alternate_exchange.rb +2 -0
  29. data/examples/guides/extensions/basic_nack.rb +1 -1
  30. data/examples/guides/extensions/dead_letter_exchange.rb +1 -1
  31. data/examples/guides/getting_started/hello_world.rb +2 -0
  32. data/examples/guides/getting_started/weathr.rb +2 -0
  33. data/examples/guides/queues/one_off_consumer.rb +2 -0
  34. data/examples/guides/queues/redeliveries.rb +4 -2
  35. data/lib/bunny.rb +8 -4
  36. data/lib/bunny/channel.rb +268 -153
  37. data/lib/bunny/channel_id_allocator.rb +6 -4
  38. data/lib/bunny/concurrent/continuation_queue.rb +34 -13
  39. data/lib/bunny/consumer_work_pool.rb +34 -6
  40. data/lib/bunny/cruby/socket.rb +48 -21
  41. data/lib/bunny/cruby/ssl_socket.rb +65 -4
  42. data/lib/bunny/exceptions.rb +25 -4
  43. data/lib/bunny/exchange.rb +24 -28
  44. data/lib/bunny/get_response.rb +1 -1
  45. data/lib/bunny/heartbeat_sender.rb +3 -2
  46. data/lib/bunny/jruby/socket.rb +23 -6
  47. data/lib/bunny/jruby/ssl_socket.rb +5 -0
  48. data/lib/bunny/queue.rb +31 -22
  49. data/lib/bunny/reader_loop.rb +31 -18
  50. data/lib/bunny/session.rb +448 -159
  51. data/lib/bunny/test_kit.rb +14 -0
  52. data/lib/bunny/timeout.rb +1 -12
  53. data/lib/bunny/transport.rb +205 -98
  54. data/lib/bunny/version.rb +1 -1
  55. data/repl +1 -1
  56. data/spec/config/enabled_plugins +1 -0
  57. data/spec/config/rabbitmq.conf +13 -0
  58. data/spec/higher_level_api/integration/basic_ack_spec.rb +175 -16
  59. data/spec/higher_level_api/integration/basic_cancel_spec.rb +77 -11
  60. data/spec/higher_level_api/integration/basic_consume_spec.rb +60 -55
  61. data/spec/higher_level_api/integration/basic_consume_with_objects_spec.rb +6 -6
  62. data/spec/higher_level_api/integration/basic_get_spec.rb +31 -7
  63. data/spec/higher_level_api/integration/basic_nack_spec.rb +22 -19
  64. data/spec/higher_level_api/integration/basic_publish_spec.rb +11 -100
  65. data/spec/higher_level_api/integration/basic_qos_spec.rb +32 -4
  66. data/spec/higher_level_api/integration/basic_reject_spec.rb +94 -16
  67. data/spec/higher_level_api/integration/basic_return_spec.rb +4 -4
  68. data/spec/higher_level_api/integration/channel_close_spec.rb +51 -10
  69. data/spec/higher_level_api/integration/channel_open_spec.rb +12 -12
  70. data/spec/higher_level_api/integration/connection_recovery_spec.rb +424 -221
  71. data/spec/higher_level_api/integration/connection_spec.rb +300 -126
  72. data/spec/higher_level_api/integration/connection_stop_spec.rb +31 -19
  73. data/spec/higher_level_api/integration/consumer_cancellation_notification_spec.rb +17 -17
  74. data/spec/higher_level_api/integration/dead_lettering_spec.rb +34 -11
  75. data/spec/higher_level_api/integration/exchange_bind_spec.rb +5 -5
  76. data/spec/higher_level_api/integration/exchange_declare_spec.rb +32 -31
  77. data/spec/higher_level_api/integration/exchange_delete_spec.rb +12 -12
  78. data/spec/higher_level_api/integration/exchange_unbind_spec.rb +5 -5
  79. data/spec/higher_level_api/integration/exclusive_queue_spec.rb +5 -5
  80. data/spec/higher_level_api/integration/heartbeat_spec.rb +26 -8
  81. data/spec/higher_level_api/integration/message_properties_access_spec.rb +49 -49
  82. data/spec/higher_level_api/integration/predeclared_exchanges_spec.rb +2 -2
  83. data/spec/higher_level_api/integration/publisher_confirms_spec.rb +156 -42
  84. data/spec/higher_level_api/integration/publishing_edge_cases_spec.rb +19 -19
  85. data/spec/higher_level_api/integration/queue_bind_spec.rb +23 -23
  86. data/spec/higher_level_api/integration/queue_declare_spec.rb +129 -34
  87. data/spec/higher_level_api/integration/queue_delete_spec.rb +2 -2
  88. data/spec/higher_level_api/integration/queue_purge_spec.rb +5 -5
  89. data/spec/higher_level_api/integration/queue_unbind_spec.rb +6 -6
  90. data/spec/higher_level_api/integration/read_only_consumer_spec.rb +9 -9
  91. data/spec/higher_level_api/integration/sender_selected_distribution_spec.rb +10 -10
  92. data/spec/higher_level_api/integration/tls_connection_spec.rb +224 -89
  93. data/spec/higher_level_api/integration/toxiproxy_spec.rb +76 -0
  94. data/spec/higher_level_api/integration/tx_commit_spec.rb +1 -1
  95. data/spec/higher_level_api/integration/tx_rollback_spec.rb +1 -1
  96. data/spec/higher_level_api/integration/with_channel_spec.rb +2 -2
  97. data/spec/issues/issue100_spec.rb +11 -11
  98. data/spec/issues/issue141_spec.rb +13 -14
  99. data/spec/issues/issue202_spec.rb +1 -1
  100. data/spec/issues/issue224_spec.rb +40 -0
  101. data/spec/issues/issue465_spec.rb +32 -0
  102. data/spec/issues/issue549_spec.rb +30 -0
  103. data/spec/issues/issue78_spec.rb +21 -24
  104. data/spec/issues/issue83_spec.rb +5 -6
  105. data/spec/issues/issue97_spec.rb +44 -45
  106. data/spec/lower_level_api/integration/basic_cancel_spec.rb +15 -16
  107. data/spec/lower_level_api/integration/basic_consume_spec.rb +20 -21
  108. data/spec/spec_helper.rb +8 -26
  109. data/spec/stress/channel_close_stress_spec.rb +64 -0
  110. data/spec/stress/channel_open_stress_spec.rb +15 -9
  111. data/spec/stress/channel_open_stress_with_single_threaded_connection_spec.rb +7 -7
  112. data/spec/stress/concurrent_consumers_stress_spec.rb +18 -16
  113. data/spec/stress/concurrent_publishers_stress_spec.rb +16 -19
  114. data/spec/stress/connection_open_close_spec.rb +9 -9
  115. data/spec/stress/merry_go_round_spec.rb +105 -0
  116. data/spec/tls/client_key.pem +49 -25
  117. data/spec/tls/generate-server-cert.sh +8 -0
  118. data/spec/tls/server-openssl.cnf +10 -0
  119. data/spec/tls/server.csr +16 -0
  120. data/spec/tls/server_key.pem +49 -25
  121. data/spec/toxiproxy_helper.rb +28 -0
  122. data/spec/unit/bunny_spec.rb +5 -5
  123. data/spec/unit/concurrent/atomic_fixnum_spec.rb +6 -6
  124. data/spec/unit/concurrent/condition_spec.rb +8 -8
  125. data/spec/unit/concurrent/linked_continuation_queue_spec.rb +2 -2
  126. data/spec/unit/concurrent/synchronized_sorted_set_spec.rb +16 -16
  127. data/spec/unit/exchange_recovery_spec.rb +39 -0
  128. data/spec/unit/version_delivery_tag_spec.rb +3 -3
  129. metadata +65 -47
  130. data/.ruby-version +0 -1
  131. data/lib/bunny/compatibility.rb +0 -24
  132. data/lib/bunny/system_timer.rb +0 -20
  133. data/spec/compatibility/queue_declare_spec.rb +0 -44
  134. data/spec/compatibility/queue_declare_with_default_channel_spec.rb +0 -33
  135. data/spec/higher_level_api/integration/basic_recover_spec.rb +0 -18
  136. data/spec/higher_level_api/integration/confirm_select_spec.rb +0 -19
  137. data/spec/higher_level_api/integration/consistent_hash_exchange_spec.rb +0 -50
  138. data/spec/higher_level_api/integration/merry_go_round_spec.rb +0 -85
  139. data/spec/stress/long_running_consumer_spec.rb +0 -83
  140. data/spec/tls/cacert.pem +0 -18
  141. data/spec/tls/client_cert.pem +0 -18
  142. data/spec/tls/server_cert.pem +0 -18
  143. 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 << 16) - 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 [Fixnum]
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 [Fixnum] i Channel id to release
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 [Fixnum] i Channel id to check
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(*args, &block)
10
- @q = ::Queue.new(*args)
9
+ def initialize
10
+ @q = []
11
+ @lock = ::Mutex.new
12
+ @cond = ::ConditionVariable.new
11
13
  end
12
14
 
13
- def push(*args)
14
- @q.push(*args)
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
- @q.pop
24
+ poll
20
25
  end
21
26
 
22
27
  def poll(timeout_in_ms = nil)
23
- if timeout_in_ms
24
- Bunny::Timeout.timeout(timeout_in_ms / 1000.0, ::Timeout::Error) do
25
- @q.pop
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
- else
28
- @q.pop
41
+ item = @q.shift
42
+ item
29
43
  end
30
44
  end
31
45
 
32
46
  def clear
33
- @q.clear
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 method_missing(selector, *args, &block)
37
- @q.__send__(selector, *args, &block)
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 shutdown
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
@@ -6,23 +6,40 @@ module Bunny
6
6
  #
7
7
  # Heavily inspired by Dalli by Mike Perham.
8
8
  # @private
9
- class Socket < TCPSocket
9
+ module Socket
10
10
  attr_accessor :options
11
11
 
12
- # IO::WaitReadable is 1.9+ only
13
- READ_RETRY_EXCEPTION_CLASSES = [Errno::EAGAIN, Errno::EWOULDBLOCK]
14
- READ_RETRY_EXCEPTION_CLASSES << IO::WaitReadable if IO.const_defined?(:WaitReadable)
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
- Timeout.timeout(options[:socket_timeout], ClientTimeout) do
18
- sock = new(host, port)
19
- if ::Socket.constants.include?('TCP_NODELAY') || ::Socket.constants.include?(:TCP_NODELAY)
20
- sock.setsockopt(::Socket::IPPROTO_TCP, ::Socket::TCP_NODELAY, true)
21
- end
22
- sock.setsockopt(::Socket::SOL_SOCKET, ::Socket::SO_KEEPALIVE, true) if options.fetch(:keepalive, true)
23
- sock.options = {:host => host, :port => port}.merge(options)
24
- sock
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
- begin
71
- while !data.empty?
72
- written = self.write_nonblock(data)
73
- data.slice!(0, written)
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
- rescue Errno::EWOULDBLOCK, Errno::EAGAIN
76
- IO.select([], [self])
77
- retry
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
- # IO::WaitReadable is 1.9+ only
12
- READ_RETRY_EXCEPTION_CLASSES = [Errno::EAGAIN, Errno::EWOULDBLOCK]
13
- READ_RETRY_EXCEPTION_CLASSES << IO::WaitReadable if IO.const_defined?(:WaitReadable)
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 => le
115
+ rescue LoadError
55
116
  puts "Could not load OpenSSL"
56
117
  end
57
118
  end
@@ -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
- super("Could not establish TCP connection to #{hostname}:#{port}: #{m}")
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