bunny 1.3.0 → 2.17.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
data/lib/bunny/exchange.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
require
|
1
|
+
require 'amq/protocol'
|
2
2
|
|
3
3
|
module Bunny
|
4
4
|
# Represents AMQP 0.9.1 exchanges.
|
@@ -7,9 +7,6 @@ module Bunny
|
|
7
7
|
# @see http://rubybunny.info/articles/extensions.html RabbitMQ Extensions guide
|
8
8
|
class Exchange
|
9
9
|
|
10
|
-
include Bunny::Compatibility
|
11
|
-
|
12
|
-
|
13
10
|
#
|
14
11
|
# API
|
15
12
|
#
|
@@ -33,12 +30,12 @@ module Bunny
|
|
33
30
|
attr_accessor :opts
|
34
31
|
|
35
32
|
|
36
|
-
# The default exchange.
|
37
|
-
#
|
38
|
-
# the following routing semantics: messages will be routed to the queue
|
39
|
-
#
|
40
|
-
# a routing key of "weather.usa.ca.sandiego" and there is a queue
|
41
|
-
#
|
33
|
+
# The default exchange. This exchange is a direct exchange that is predefined by the broker
|
34
|
+
# and that cannot be removed. Every queue is bound to this exchange by default with
|
35
|
+
# the following routing semantics: messages will be routed to the queue with the same
|
36
|
+
# name as the message's routing key. In other words, if a message is published with
|
37
|
+
# a routing key of "weather.usa.ca.sandiego" and there is a queue with this name,
|
38
|
+
# the message will be routed to the queue.
|
42
39
|
#
|
43
40
|
# @param [Bunny::Channel] channel_or_connection Channel to use. {Bunny::Session} instances
|
44
41
|
# are only supported for backwards compatibility.
|
@@ -46,11 +43,11 @@ module Bunny
|
|
46
43
|
# @example Publishing a messages to the tasks queue
|
47
44
|
# channel = Bunny::Channel.new(connection)
|
48
45
|
# tasks_queue = channel.queue("tasks")
|
49
|
-
# Bunny::Exchange.default(channel).publish("make clean", routing_key => "tasks")
|
46
|
+
# Bunny::Exchange.default(channel).publish("make clean", :routing_key => "tasks")
|
50
47
|
#
|
51
48
|
# @see http://rubybunny.info/articles/exchanges.html Exchanges and Publishing guide
|
52
49
|
# @see http://www.rabbitmq.com/resources/specs/amqp0-9-1.pdf AMQP 0.9.1 specification (Section 2.1.2.4)
|
53
|
-
# @note Do not confuse default exchange with amq.direct: amq.direct is a pre-defined direct
|
50
|
+
# @note Do not confuse the default exchange with amq.direct: amq.direct is a pre-defined direct
|
54
51
|
# exchange that doesn't have any special routing semantics.
|
55
52
|
# @return [Exchange] An instance that corresponds to the default exchange (of type direct).
|
56
53
|
# @api public
|
@@ -58,11 +55,10 @@ module Bunny
|
|
58
55
|
self.new(channel_or_connection, :direct, AMQ::Protocol::EMPTY_STRING, :no_declare => true)
|
59
56
|
end
|
60
57
|
|
61
|
-
# @param [Bunny::Channel]
|
62
|
-
#
|
63
|
-
# @param [
|
64
|
-
# @param [
|
65
|
-
# @param [Hash] opts Exchange properties
|
58
|
+
# @param [Bunny::Channel] channel Channel this exchange will use.
|
59
|
+
# @param [Symbol,String] type Exchange type
|
60
|
+
# @param [String] name Exchange name
|
61
|
+
# @param [Hash] opts Exchange properties
|
66
62
|
#
|
67
63
|
# @option opts [Boolean] :durable (false) Should this exchange be durable?
|
68
64
|
# @option opts [Boolean] :auto_delete (false) Should this exchange be automatically deleted when it is no longer used?
|
@@ -75,10 +71,8 @@ module Bunny
|
|
75
71
|
# @see http://rubybunny.info/articles/exchanges.html Exchanges and Publishing guide
|
76
72
|
# @see http://rubybunny.info/articles/extensions.html RabbitMQ Extensions guide
|
77
73
|
# @api public
|
78
|
-
def initialize(
|
79
|
-
|
80
|
-
# we just use default channel from it. MK.
|
81
|
-
@channel = channel_from(channel_or_connection)
|
74
|
+
def initialize(channel, type, name, opts = {})
|
75
|
+
@channel = channel
|
82
76
|
@name = name
|
83
77
|
@type = type
|
84
78
|
@options = self.class.add_default_options(name, opts)
|
@@ -88,6 +82,8 @@ module Bunny
|
|
88
82
|
@internal = @options[:internal]
|
89
83
|
@arguments = @options[:arguments]
|
90
84
|
|
85
|
+
@bindings = Set.new
|
86
|
+
|
91
87
|
declare! unless opts[:no_declare] || predeclared? || (@name == AMQ::Protocol::EMPTY_STRING)
|
92
88
|
|
93
89
|
@channel.register_exchange(self)
|
@@ -177,6 +173,7 @@ module Bunny
|
|
177
173
|
# @api public
|
178
174
|
def bind(source, opts = {})
|
179
175
|
@channel.exchange_bind(source, self, opts)
|
176
|
+
@bindings.add(source: source, opts: opts)
|
180
177
|
|
181
178
|
self
|
182
179
|
end
|
@@ -197,6 +194,7 @@ module Bunny
|
|
197
194
|
# @api public
|
198
195
|
def unbind(source, opts = {})
|
199
196
|
@channel.exchange_unbind(source, self, opts)
|
197
|
+
@bindings.delete(source: source, opts: opts)
|
200
198
|
|
201
199
|
self
|
202
200
|
end
|
@@ -222,8 +220,11 @@ module Bunny
|
|
222
220
|
|
223
221
|
# @private
|
224
222
|
def recover_from_network_failure
|
225
|
-
|
226
|
-
|
223
|
+
declare! unless @options[:no_declare] ||predefined?
|
224
|
+
|
225
|
+
@bindings.each do |b|
|
226
|
+
bind(b[:source], b[:opts])
|
227
|
+
end
|
227
228
|
end
|
228
229
|
|
229
230
|
|
@@ -253,11 +254,6 @@ module Bunny
|
|
253
254
|
@channel.exchange_declare(@name, @type, @options)
|
254
255
|
end
|
255
256
|
|
256
|
-
# @private
|
257
|
-
def self.add_default_options(name, opts, block)
|
258
|
-
{ :exchange => name, :nowait => (block.nil? && !name.empty?) }.merge(opts)
|
259
|
-
end
|
260
|
-
|
261
257
|
# @private
|
262
258
|
def self.add_default_options(name, opts)
|
263
259
|
# :nowait is always false for Bunny
|
data/lib/bunny/get_response.rb
CHANGED
@@ -29,6 +29,7 @@ module Bunny
|
|
29
29
|
@interval = [(period / 2) - 1, 0.4].max
|
30
30
|
|
31
31
|
@thread = Thread.new(&method(:run))
|
32
|
+
@thread.report_on_exception = false if @thread.respond_to?(:report_on_exception)
|
32
33
|
end
|
33
34
|
end
|
34
35
|
|
@@ -62,8 +63,8 @@ module Bunny
|
|
62
63
|
now = Time.now
|
63
64
|
|
64
65
|
if now > (@last_activity_time + @interval)
|
65
|
-
@logger.debug "Sending a heartbeat, last activity time: #{@last_activity_time}, interval (s): #{@interval}"
|
66
|
-
@transport.write_without_timeout(AMQ::Protocol::HeartbeatFrame.encode)
|
66
|
+
@logger.debug { "Sending a heartbeat, last activity time: #{@last_activity_time}, interval (s): #{@interval}" }
|
67
|
+
@transport.write_without_timeout(AMQ::Protocol::HeartbeatFrame.encode, true)
|
67
68
|
end
|
68
69
|
end
|
69
70
|
end
|
data/lib/bunny/jruby/socket.rb
CHANGED
@@ -5,7 +5,22 @@ module Bunny
|
|
5
5
|
# TCP socket extension that uses Socket#readpartial to avoid excessive CPU
|
6
6
|
# burn after some time. See issue #165.
|
7
7
|
# @private
|
8
|
-
|
8
|
+
module Socket
|
9
|
+
include Bunny::Socket
|
10
|
+
|
11
|
+
def self.open(host, port, options = {})
|
12
|
+
socket = ::Socket.tcp(host, port, nil, nil,
|
13
|
+
connect_timeout: options[:connect_timeout])
|
14
|
+
if ::Socket.constants.include?('TCP_NODELAY') || ::Socket.constants.include?(:TCP_NODELAY)
|
15
|
+
socket.setsockopt(::Socket::IPPROTO_TCP, ::Socket::TCP_NODELAY, true)
|
16
|
+
end
|
17
|
+
socket.setsockopt(::Socket::SOL_SOCKET, ::Socket::SO_KEEPALIVE, true) if options.fetch(:keepalive, true)
|
18
|
+
socket.extend self
|
19
|
+
socket.options = { :host => host, :port => port }.merge(options)
|
20
|
+
socket
|
21
|
+
rescue Errno::ETIMEDOUT
|
22
|
+
raise ClientTimeout
|
23
|
+
end
|
9
24
|
|
10
25
|
# Reads given number of bytes with an optional timeout
|
11
26
|
#
|
@@ -15,17 +30,17 @@ module Bunny
|
|
15
30
|
# @return [String] Data read from the socket
|
16
31
|
# @api public
|
17
32
|
def read_fully(count, timeout = nil)
|
18
|
-
return nil if @__bunny_socket_eof_flag__
|
19
|
-
|
20
33
|
value = ''
|
34
|
+
|
21
35
|
begin
|
22
36
|
loop do
|
23
|
-
value <<
|
37
|
+
value << read_nonblock(count - value.bytesize)
|
24
38
|
break if value.bytesize >= count
|
25
39
|
end
|
26
40
|
rescue EOFError
|
27
|
-
#
|
28
|
-
|
41
|
+
# JRuby specific fix via https://github.com/jruby/jruby/issues/1694#issuecomment-54873532
|
42
|
+
IO.select([self], nil, nil, timeout)
|
43
|
+
retry
|
29
44
|
rescue *READ_RETRY_EXCEPTION_CLASSES
|
30
45
|
if IO.select([self], nil, nil, timeout)
|
31
46
|
retry
|
@@ -33,8 +48,10 @@ module Bunny
|
|
33
48
|
raise Timeout::Error, "IO timeout when reading #{count} bytes"
|
34
49
|
end
|
35
50
|
end
|
51
|
+
|
36
52
|
value
|
37
53
|
end # read_fully
|
54
|
+
|
38
55
|
end
|
39
56
|
end
|
40
57
|
end
|
@@ -8,6 +8,11 @@ module Bunny
|
|
8
8
|
# methods found in Bunny::Socket.
|
9
9
|
class SSLSocket < Bunny::SSLSocket
|
10
10
|
|
11
|
+
def initialize(*args)
|
12
|
+
super
|
13
|
+
@__bunny_socket_eof_flag__ = false
|
14
|
+
end
|
15
|
+
|
11
16
|
# Reads given number of bytes with an optional timeout
|
12
17
|
#
|
13
18
|
# @param [Integer] count How many bytes to read
|
data/lib/bunny/queue.rb
CHANGED
@@ -1,4 +1,3 @@
|
|
1
|
-
require "bunny/compatibility"
|
2
1
|
require "bunny/get_response"
|
3
2
|
|
4
3
|
module Bunny
|
@@ -8,9 +7,6 @@ module Bunny
|
|
8
7
|
# @see http://rubybunny.info/articles/extensions.html RabbitMQ Extensions guide
|
9
8
|
class Queue
|
10
9
|
|
11
|
-
include Bunny::Compatibility
|
12
|
-
|
13
|
-
|
14
10
|
#
|
15
11
|
# API
|
16
12
|
#
|
@@ -22,8 +18,7 @@ module Bunny
|
|
22
18
|
# @return [Hash] Options this queue was created with
|
23
19
|
attr_reader :options
|
24
20
|
|
25
|
-
# @param [Bunny::Channel]
|
26
|
-
# backwards compatibility with 0.8.
|
21
|
+
# @param [Bunny::Channel] channel Channel this queue will use.
|
27
22
|
# @param [String] name Queue name. Pass an empty string to make RabbitMQ generate a unique one.
|
28
23
|
# @param [Hash] opts Queue properties
|
29
24
|
#
|
@@ -36,13 +31,12 @@ module Bunny
|
|
36
31
|
# @see http://rubybunny.info/articles/queues.html Queues and Consumers guide
|
37
32
|
# @see http://rubybunny.info/articles/extensions.html RabbitMQ Extensions guide
|
38
33
|
# @api public
|
39
|
-
def initialize(
|
34
|
+
def initialize(channel, name = AMQ::Protocol::EMPTY_STRING, opts = {})
|
40
35
|
# old Bunny versions pass a connection here. In that case,
|
41
36
|
# we just use default channel from it. MK.
|
42
|
-
@channel =
|
37
|
+
@channel = channel
|
43
38
|
@name = name
|
44
39
|
@options = self.class.add_default_options(name, opts)
|
45
|
-
@consumers = Hash.new
|
46
40
|
|
47
41
|
@durable = @options[:durable]
|
48
42
|
@exclusive = @options[:exclusive]
|
@@ -93,6 +87,15 @@ module Bunny
|
|
93
87
|
@arguments
|
94
88
|
end
|
95
89
|
|
90
|
+
def to_s
|
91
|
+
oid = ("0x%x" % (self.object_id << 1))
|
92
|
+
"<#{self.class.name}:#{oid} @name=\"#{name}\" channel=#{@channel.to_s} @durable=#{@durable} @auto_delete=#{@auto_delete} @exclusive=#{@exclusive} @arguments=#{@arguments}>"
|
93
|
+
end
|
94
|
+
|
95
|
+
def inspect
|
96
|
+
to_s
|
97
|
+
end
|
98
|
+
|
96
99
|
# Binds queue to an exchange
|
97
100
|
#
|
98
101
|
# @param [Bunny::Exchange,String] exchange Exchange to bind to
|
@@ -152,9 +155,9 @@ module Bunny
|
|
152
155
|
#
|
153
156
|
# @param [Hash] opts Options
|
154
157
|
#
|
158
|
+
# @option opts [Boolean] :ack (false) [DEPRECATED] Use :manual_ack instead
|
155
159
|
# @option opts [Boolean] :manual_ack (false) Will this consumer use manual acknowledgements?
|
156
160
|
# @option opts [Boolean] :exclusive (false) Should this consumer be exclusive for this queue?
|
157
|
-
# @option opts [Boolean] :block (false) Should the call block calling thread?
|
158
161
|
# @option opts [#call] :on_cancellation Block to execute when this consumer is cancelled remotely (e.g. via the RabbitMQ Management plugin)
|
159
162
|
# @option opts [String] :consumer_tag Unique consumer identifier. It is usually recommended to let Bunny generate it for you.
|
160
163
|
# @option opts [Hash] :arguments ({}) Additional (optional) arguments, typically used by RabbitMQ extensions
|
@@ -163,17 +166,22 @@ module Bunny
|
|
163
166
|
# @api public
|
164
167
|
def subscribe(opts = {
|
165
168
|
:consumer_tag => @channel.generate_consumer_tag,
|
166
|
-
:
|
169
|
+
:manual_ack => false,
|
167
170
|
:exclusive => false,
|
168
171
|
:block => false,
|
169
172
|
:on_cancellation => nil
|
170
173
|
}, &block)
|
171
174
|
|
175
|
+
unless opts[:ack].nil?
|
176
|
+
warn "[DEPRECATION] `:ack` is deprecated. Please use `:manual_ack` instead."
|
177
|
+
opts[:manual_ack] = opts[:ack]
|
178
|
+
end
|
179
|
+
|
172
180
|
ctag = opts.fetch(:consumer_tag, @channel.generate_consumer_tag)
|
173
181
|
consumer = Consumer.new(@channel,
|
174
182
|
self,
|
175
183
|
ctag,
|
176
|
-
!
|
184
|
+
!opts[:manual_ack],
|
177
185
|
opts[:exclusive],
|
178
186
|
opts[:arguments])
|
179
187
|
|
@@ -208,7 +216,8 @@ module Bunny
|
|
208
216
|
|
209
217
|
# @param [Hash] opts Options
|
210
218
|
#
|
211
|
-
# @option opts [Boolean] :ack (false)
|
219
|
+
# @option opts [Boolean] :ack (false) [DEPRECATED] Use :manual_ack instead
|
220
|
+
# @option opts [Boolean] :manual_ack (false) Will the message be acknowledged manually?
|
212
221
|
#
|
213
222
|
# @return [Array] Triple of delivery info, message properties and message content.
|
214
223
|
# If the queue is empty, all three will be nils.
|
@@ -229,12 +238,17 @@ module Bunny
|
|
229
238
|
#
|
230
239
|
# puts "This is the message: " + payload + "\n\n"
|
231
240
|
# conn.close
|
232
|
-
def pop(opts = {:
|
241
|
+
def pop(opts = {:manual_ack => false}, &block)
|
242
|
+
unless opts[:ack].nil?
|
243
|
+
warn "[DEPRECATION] `:ack` is deprecated. Please use `:manual_ack` instead."
|
244
|
+
opts[:manual_ack] = opts[:ack]
|
245
|
+
end
|
246
|
+
|
233
247
|
get_response, properties, content = @channel.basic_get(@name, opts)
|
234
248
|
|
235
249
|
if block
|
236
250
|
if properties
|
237
|
-
di = GetResponse.new(get_response,
|
251
|
+
di = GetResponse.new(get_response, @channel)
|
238
252
|
mp = MessageProperties.new(properties)
|
239
253
|
|
240
254
|
block.call(di, mp, content)
|
@@ -243,7 +257,7 @@ module Bunny
|
|
243
257
|
end
|
244
258
|
else
|
245
259
|
if properties
|
246
|
-
di = GetResponse.new(get_response,
|
260
|
+
di = GetResponse.new(get_response, @channel)
|
247
261
|
mp = MessageProperties.new(properties)
|
248
262
|
[di, mp, content]
|
249
263
|
else
|
@@ -326,7 +340,7 @@ module Bunny
|
|
326
340
|
# TODO: inject and use logger
|
327
341
|
# puts "Recovering queue #{@name}"
|
328
342
|
begin
|
329
|
-
declare!
|
343
|
+
declare! unless @options[:no_declare]
|
330
344
|
|
331
345
|
@channel.register_queue(self)
|
332
346
|
rescue Exception => e
|
@@ -358,11 +372,6 @@ module Bunny
|
|
358
372
|
|
359
373
|
protected
|
360
374
|
|
361
|
-
# @private
|
362
|
-
def self.add_default_options(name, opts, block)
|
363
|
-
{ :queue => name, :nowait => (block.nil? && !name.empty?) }.merge(opts)
|
364
|
-
end
|
365
|
-
|
366
375
|
# @private
|
367
376
|
def self.add_default_options(name, opts)
|
368
377
|
# :nowait is always false for Bunny
|
data/lib/bunny/reader_loop.rb
CHANGED
@@ -9,13 +9,17 @@ module Bunny
|
|
9
9
|
# @private
|
10
10
|
class ReaderLoop
|
11
11
|
|
12
|
-
def initialize(transport, session,
|
13
|
-
@transport
|
14
|
-
@session
|
15
|
-
@
|
16
|
-
@logger
|
12
|
+
def initialize(transport, session, session_error_handler)
|
13
|
+
@transport = transport
|
14
|
+
@session = session
|
15
|
+
@session_error_handler = session_error_handler
|
16
|
+
@logger = @session.logger
|
17
17
|
|
18
|
-
@mutex
|
18
|
+
@mutex = Mutex.new
|
19
|
+
|
20
|
+
@stopping = false
|
21
|
+
@stopped = false
|
22
|
+
@network_is_down = false
|
19
23
|
end
|
20
24
|
|
21
25
|
|
@@ -33,15 +37,17 @@ module Bunny
|
|
33
37
|
begin
|
34
38
|
break if @mutex.synchronize { @stopping || @stopped || @network_is_down }
|
35
39
|
run_once
|
36
|
-
rescue AMQ::Protocol::EmptyResponseError, IOError, SystemCallError
|
40
|
+
rescue AMQ::Protocol::EmptyResponseError, IOError, SystemCallError, Timeout::Error,
|
41
|
+
OpenSSL::OpenSSLError => e
|
37
42
|
break if terminate? || @session.closing? || @session.closed?
|
38
43
|
|
39
|
-
log_exception(e)
|
40
44
|
@network_is_down = true
|
41
45
|
if @session.automatically_recover?
|
46
|
+
log_exception(e, level: :warn)
|
42
47
|
@session.handle_network_failure(e)
|
43
48
|
else
|
44
|
-
|
49
|
+
log_exception(e)
|
50
|
+
@session_error_handler.raise(Bunny::NetworkFailure.new("detected a network failure: #{e.message}", e))
|
45
51
|
end
|
46
52
|
rescue ShutdownSignal => _
|
47
53
|
@mutex.synchronize { @stopping = true }
|
@@ -52,9 +58,9 @@ module Bunny
|
|
52
58
|
log_exception(e)
|
53
59
|
|
54
60
|
@network_is_down = true
|
55
|
-
@
|
61
|
+
@session_error_handler.raise(Bunny::NetworkFailure.new("caught an unexpected exception in the network loop: #{e.message}", e))
|
56
62
|
end
|
57
|
-
rescue Errno::EBADF =>
|
63
|
+
rescue Errno::EBADF => _ebadf
|
58
64
|
break if terminate?
|
59
65
|
# ignored, happens when we loop after the transport has already been closed
|
60
66
|
@mutex.synchronize { @stopping = true }
|
@@ -92,11 +98,11 @@ module Bunny
|
|
92
98
|
end
|
93
99
|
|
94
100
|
def stopped?
|
95
|
-
@mutex.synchronize { @stopped
|
101
|
+
@mutex.synchronize { @stopped }
|
96
102
|
end
|
97
103
|
|
98
104
|
def stopping?
|
99
|
-
@mutex.synchronize { @stopping
|
105
|
+
@mutex.synchronize { @stopping }
|
100
106
|
end
|
101
107
|
|
102
108
|
def terminate_with(e)
|
@@ -110,7 +116,14 @@ module Bunny
|
|
110
116
|
end
|
111
117
|
|
112
118
|
def join
|
113
|
-
|
119
|
+
# Thread#join can/would trigger a re-raise of an unhandled exception in this thread.
|
120
|
+
# In addition, Thread.handle_interrupt can be used by other libraries or application code
|
121
|
+
# that would make this join operation fail with an obscure exception.
|
122
|
+
# So we try to save everyone some really unpleasant debugging time by introducing
|
123
|
+
# this condition which typically would not evaluate to true anyway.
|
124
|
+
#
|
125
|
+
# See ruby-amqp/bunny#589 and ruby-amqp/bunny#590 for background.
|
126
|
+
@thread.join if @thread && @thread != Thread.current
|
114
127
|
end
|
115
128
|
|
116
129
|
def kill
|
@@ -122,12 +135,12 @@ module Bunny
|
|
122
135
|
|
123
136
|
protected
|
124
137
|
|
125
|
-
def log_exception(e)
|
138
|
+
def log_exception(e, level: :error)
|
126
139
|
if !(io_error?(e) && (@session.closing? || @session.closed?))
|
127
|
-
@logger.
|
128
|
-
@logger.
|
140
|
+
@logger.send level, "Exception in the reader loop: #{e.class.name}: #{e.message}"
|
141
|
+
@logger.send level, "Backtrace: "
|
129
142
|
e.backtrace.each do |line|
|
130
|
-
@logger.
|
143
|
+
@logger.send level, "\t#{line}"
|
131
144
|
end
|
132
145
|
end
|
133
146
|
end
|