bunny 1.3.0 → 2.17.0

Sign up to get free protection for your applications and to get access to all the features.
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