bunny 2.7.4 → 2.22.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/README.md +61 -35
- data/lib/bunny/channel.rb +186 -50
- data/lib/bunny/channel_id_allocator.rb +3 -1
- data/lib/bunny/consumer.rb +2 -2
- data/lib/bunny/consumer_work_pool.rb +2 -1
- data/lib/bunny/cruby/socket.rb +3 -0
- data/lib/bunny/cruby/ssl_socket.rb +6 -1
- data/lib/bunny/delivery_info.rb +1 -1
- data/lib/bunny/heartbeat_sender.rb +2 -1
- data/lib/bunny/jruby/ssl_socket.rb +5 -0
- data/lib/bunny/queue.rb +36 -8
- data/lib/bunny/reader_loop.rb +22 -10
- data/lib/bunny/session.rb +152 -65
- data/lib/bunny/test_kit.rb +14 -0
- data/lib/bunny/transport.rb +132 -49
- data/lib/bunny/version.rb +1 -1
- data/lib/bunny.rb +45 -4
- metadata +37 -225
- data/.github/ISSUE_TEMPLATE.md +0 -18
- data/.gitignore +0 -28
- data/.rspec +0 -1
- data/.travis.yml +0 -20
- data/.yardopts +0 -8
- data/CONTRIBUTING.md +0 -111
- data/ChangeLog.md +0 -1831
- data/Gemfile +0 -53
- data/LICENSE +0 -21
- data/Rakefile +0 -46
- data/benchmarks/basic_publish/with_128K_messages.rb +0 -35
- data/benchmarks/basic_publish/with_1k_messages.rb +0 -35
- data/benchmarks/basic_publish/with_4K_messages.rb +0 -35
- data/benchmarks/basic_publish/with_64K_messages.rb +0 -35
- data/benchmarks/channel_open.rb +0 -28
- data/benchmarks/mutex_and_monitor.rb +0 -42
- data/benchmarks/queue_declare.rb +0 -29
- data/benchmarks/queue_declare_and_bind.rb +0 -29
- data/benchmarks/queue_declare_bind_and_delete.rb +0 -29
- data/benchmarks/synchronized_sorted_set.rb +0 -53
- data/benchmarks/write_vs_write_nonblock.rb +0 -49
- data/bin/ci/before_build +0 -46
- data/bunny.gemspec +0 -35
- data/docker/Dockerfile +0 -16
- data/docker/docker-entrypoint.sh +0 -37
- data/docker-compose.yml +0 -18
- data/examples/connection/authentication_failure.rb +0 -16
- data/examples/connection/automatic_recovery_with_basic_get.rb +0 -40
- data/examples/connection/automatic_recovery_with_client_named_queues.rb +0 -36
- data/examples/connection/automatic_recovery_with_multiple_consumers.rb +0 -46
- data/examples/connection/automatic_recovery_with_republishing.rb +0 -109
- data/examples/connection/automatic_recovery_with_server_named_queues.rb +0 -35
- data/examples/connection/channel_level_exception.rb +0 -27
- data/examples/connection/disabled_automatic_recovery.rb +0 -34
- data/examples/connection/heartbeat.rb +0 -17
- data/examples/connection/manually_reconnecting_consumer.rb +0 -23
- data/examples/connection/manually_reconnecting_publisher.rb +0 -28
- data/examples/connection/unknown_host.rb +0 -16
- data/examples/consumers/high_and_low_priority.rb +0 -50
- data/examples/guides/exchanges/direct_exchange_routing.rb +0 -36
- data/examples/guides/exchanges/fanout_exchange_routing.rb +0 -28
- data/examples/guides/exchanges/headers_exchange_routing.rb +0 -31
- data/examples/guides/exchanges/mandatory_messages.rb +0 -30
- data/examples/guides/extensions/alternate_exchange.rb +0 -30
- data/examples/guides/extensions/basic_nack.rb +0 -33
- data/examples/guides/extensions/connection_blocked.rb +0 -35
- data/examples/guides/extensions/consumer_cancellation_notification.rb +0 -39
- data/examples/guides/extensions/dead_letter_exchange.rb +0 -32
- data/examples/guides/extensions/exchange_to_exchange_bindings.rb +0 -29
- data/examples/guides/extensions/per_message_ttl.rb +0 -36
- data/examples/guides/extensions/per_queue_message_ttl.rb +0 -36
- data/examples/guides/extensions/publisher_confirms.rb +0 -28
- data/examples/guides/extensions/queue_lease.rb +0 -26
- data/examples/guides/extensions/sender_selected_distribution.rb +0 -32
- data/examples/guides/getting_started/blabbr.rb +0 -27
- data/examples/guides/getting_started/hello_world.rb +0 -22
- data/examples/guides/getting_started/weathr.rb +0 -49
- data/examples/guides/queues/one_off_consumer.rb +0 -25
- data/examples/guides/queues/redeliveries.rb +0 -81
- data/profiling/basic_publish/with_4K_messages.rb +0 -33
- data/repl +0 -3
- data/spec/config/enabled_plugins +0 -1
- data/spec/config/rabbitmq.config +0 -19
- data/spec/higher_level_api/integration/basic_ack_spec.rb +0 -230
- data/spec/higher_level_api/integration/basic_cancel_spec.rb +0 -142
- data/spec/higher_level_api/integration/basic_consume_spec.rb +0 -349
- data/spec/higher_level_api/integration/basic_consume_with_objects_spec.rb +0 -54
- data/spec/higher_level_api/integration/basic_get_spec.rb +0 -80
- data/spec/higher_level_api/integration/basic_nack_spec.rb +0 -82
- data/spec/higher_level_api/integration/basic_publish_spec.rb +0 -74
- data/spec/higher_level_api/integration/basic_qos_spec.rb +0 -57
- data/spec/higher_level_api/integration/basic_reject_spec.rb +0 -152
- data/spec/higher_level_api/integration/basic_return_spec.rb +0 -33
- data/spec/higher_level_api/integration/channel_close_spec.rb +0 -25
- data/spec/higher_level_api/integration/channel_open_spec.rb +0 -57
- data/spec/higher_level_api/integration/connection_recovery_spec.rb +0 -471
- data/spec/higher_level_api/integration/connection_spec.rb +0 -559
- data/spec/higher_level_api/integration/connection_stop_spec.rb +0 -83
- data/spec/higher_level_api/integration/consumer_cancellation_notification_spec.rb +0 -128
- data/spec/higher_level_api/integration/dead_lettering_spec.rb +0 -75
- data/spec/higher_level_api/integration/exchange_bind_spec.rb +0 -31
- data/spec/higher_level_api/integration/exchange_declare_spec.rb +0 -237
- data/spec/higher_level_api/integration/exchange_delete_spec.rb +0 -105
- data/spec/higher_level_api/integration/exchange_unbind_spec.rb +0 -40
- data/spec/higher_level_api/integration/exclusive_queue_spec.rb +0 -28
- data/spec/higher_level_api/integration/heartbeat_spec.rb +0 -49
- data/spec/higher_level_api/integration/merry_go_round_spec.rb +0 -85
- data/spec/higher_level_api/integration/message_properties_access_spec.rb +0 -95
- data/spec/higher_level_api/integration/predeclared_exchanges_spec.rb +0 -24
- data/spec/higher_level_api/integration/publisher_confirms_spec.rb +0 -191
- data/spec/higher_level_api/integration/publishing_edge_cases_spec.rb +0 -87
- data/spec/higher_level_api/integration/queue_bind_spec.rb +0 -109
- data/spec/higher_level_api/integration/queue_declare_spec.rb +0 -221
- data/spec/higher_level_api/integration/queue_delete_spec.rb +0 -41
- data/spec/higher_level_api/integration/queue_purge_spec.rb +0 -30
- data/spec/higher_level_api/integration/queue_unbind_spec.rb +0 -54
- data/spec/higher_level_api/integration/read_only_consumer_spec.rb +0 -60
- data/spec/higher_level_api/integration/sender_selected_distribution_spec.rb +0 -36
- data/spec/higher_level_api/integration/tls_connection_spec.rb +0 -222
- data/spec/higher_level_api/integration/tx_commit_spec.rb +0 -21
- data/spec/higher_level_api/integration/tx_rollback_spec.rb +0 -21
- data/spec/higher_level_api/integration/with_channel_spec.rb +0 -25
- data/spec/issues/issue100_spec.rb +0 -42
- data/spec/issues/issue141_spec.rb +0 -43
- data/spec/issues/issue202_spec.rb +0 -15
- data/spec/issues/issue224_spec.rb +0 -40
- data/spec/issues/issue465_spec.rb +0 -32
- data/spec/issues/issue78_spec.rb +0 -72
- data/spec/issues/issue83_spec.rb +0 -30
- data/spec/issues/issue97_attachment.json +0 -1
- data/spec/issues/issue97_spec.rb +0 -175
- data/spec/lower_level_api/integration/basic_cancel_spec.rb +0 -83
- data/spec/lower_level_api/integration/basic_consume_spec.rb +0 -99
- data/spec/spec_helper.rb +0 -51
- data/spec/stress/channel_close_stress_spec.rb +0 -64
- data/spec/stress/channel_open_stress_spec.rb +0 -84
- data/spec/stress/channel_open_stress_with_single_threaded_connection_spec.rb +0 -28
- data/spec/stress/concurrent_consumers_stress_spec.rb +0 -71
- data/spec/stress/concurrent_publishers_stress_spec.rb +0 -54
- data/spec/stress/connection_open_close_spec.rb +0 -52
- data/spec/stress/long_running_consumer_spec.rb +0 -84
- data/spec/tls/ca_certificate.pem +0 -29
- data/spec/tls/ca_key.pem +0 -52
- data/spec/tls/client_certificate.pem +0 -29
- data/spec/tls/client_key.pem +0 -51
- data/spec/tls/generate-server-cert.sh +0 -8
- data/spec/tls/server-openssl.cnf +0 -10
- data/spec/tls/server.csr +0 -16
- data/spec/tls/server_certificate.pem +0 -29
- data/spec/tls/server_key.pem +0 -51
- data/spec/unit/bunny_spec.rb +0 -15
- data/spec/unit/concurrent/atomic_fixnum_spec.rb +0 -35
- data/spec/unit/concurrent/condition_spec.rb +0 -82
- data/spec/unit/concurrent/linked_continuation_queue_spec.rb +0 -35
- data/spec/unit/concurrent/synchronized_sorted_set_spec.rb +0 -73
- data/spec/unit/exchange_recovery_spec.rb +0 -39
- data/spec/unit/version_delivery_tag_spec.rb +0 -28
data/lib/bunny/channel.rb
CHANGED
@@ -143,6 +143,10 @@ module Bunny
|
|
143
143
|
attr_reader :work_pool
|
144
144
|
# @return [Integer] Next publisher confirmations sequence index
|
145
145
|
attr_reader :next_publish_seq_no
|
146
|
+
# @return [Integer] Offset for the confirmations sequence index.
|
147
|
+
# This will be set to the current sequence index during automatic network failure recovery
|
148
|
+
# to keep the sequence monotonic for the user and abstract the reset from the protocol
|
149
|
+
attr_reader :delivery_tag_offset
|
146
150
|
# @return [Hash<String, Bunny::Queue>] Queue instances declared on this channel
|
147
151
|
attr_reader :queues
|
148
152
|
# @return [Hash<String, Bunny::Exchange>] Exchange instances declared on this channel
|
@@ -169,6 +173,17 @@ module Bunny
|
|
169
173
|
@connection = connection
|
170
174
|
@logger = connection.logger
|
171
175
|
@id = id || @connection.next_channel_id
|
176
|
+
|
177
|
+
# channel allocator is exhausted
|
178
|
+
if @id < 0
|
179
|
+
msg = "Cannot open a channel: max number of channels on connection reached. Connection channel_max value: #{@connection.channel_max}"
|
180
|
+
@logger.error(msg)
|
181
|
+
|
182
|
+
raise msg
|
183
|
+
else
|
184
|
+
@logger.debug { "Allocated channel id: #{@id}" }
|
185
|
+
end
|
186
|
+
|
172
187
|
@status = :opening
|
173
188
|
|
174
189
|
@connection.register_channel(self)
|
@@ -233,6 +248,9 @@ module Bunny
|
|
233
248
|
# {Bunny::Queue}, {Bunny::Exchange} and {Bunny::Consumer} instances.
|
234
249
|
# @api public
|
235
250
|
def close
|
251
|
+
# see bunny#528
|
252
|
+
raise_if_no_longer_open!
|
253
|
+
|
236
254
|
@connection.close_channel(self)
|
237
255
|
@status = :closed
|
238
256
|
@work_pool.shutdown
|
@@ -251,15 +269,6 @@ module Bunny
|
|
251
269
|
@status == :closed
|
252
270
|
end
|
253
271
|
|
254
|
-
def to_s
|
255
|
-
oid = ("0x%x" % (self.object_id << 1))
|
256
|
-
"<#{self.class.name}:#{oid} number=#{@channel.id} @open=#{open?} connection=#{@connection.to_s}>"
|
257
|
-
end
|
258
|
-
|
259
|
-
def inspect
|
260
|
-
to_s
|
261
|
-
end
|
262
|
-
|
263
272
|
#
|
264
273
|
# @group Backwards compatibility with 0.8.0
|
265
274
|
#
|
@@ -369,7 +378,7 @@ module Bunny
|
|
369
378
|
# @see http://rubybunny.info/articles/exchanges.html Exchanges and Publishing guide
|
370
379
|
# @api public
|
371
380
|
def default_exchange
|
372
|
-
Exchange.default(self)
|
381
|
+
@default_exchange ||= Exchange.default(self)
|
373
382
|
end
|
374
383
|
|
375
384
|
# Declares a headers exchange or looks it up in the cache of previously
|
@@ -387,7 +396,7 @@ module Bunny
|
|
387
396
|
# @see http://rubybunny.info/articles/exchanges.html Exchanges and Publishing guide
|
388
397
|
# @see http://rubybunny.info/articles/extensions.html RabbitMQ Extensions to AMQP 0.9.1 guide
|
389
398
|
def exchange(name, opts = {})
|
390
|
-
Exchange.new(self, opts.fetch(:type, :direct), name, opts)
|
399
|
+
find_exchange(name) || Exchange.new(self, opts.fetch(:type, :direct), name, opts)
|
391
400
|
end
|
392
401
|
|
393
402
|
# @endgroup
|
@@ -403,18 +412,87 @@ module Bunny
|
|
403
412
|
# @option opts [Boolean] :durable (false) Should this queue be durable?
|
404
413
|
# @option opts [Boolean] :auto-delete (false) Should this queue be automatically deleted when the last consumer disconnects?
|
405
414
|
# @option opts [Boolean] :exclusive (false) Should this queue be exclusive (only can be used by this connection, removed when the connection is closed)?
|
406
|
-
# @option opts [
|
415
|
+
# @option opts [Hash] :arguments ({}) Additional optional arguments (typically used by RabbitMQ extensions and plugins)
|
407
416
|
#
|
408
417
|
# @return [Bunny::Queue] Queue that was declared or looked up in the cache
|
409
418
|
# @see http://rubybunny.info/articles/queues.html Queues and Consumers guide
|
410
419
|
# @see http://rubybunny.info/articles/extensions.html RabbitMQ Extensions guide
|
411
420
|
# @api public
|
412
421
|
def queue(name = AMQ::Protocol::EMPTY_STRING, opts = {})
|
422
|
+
throw ArgumentError.new("queue name must not be nil") if name.nil?
|
423
|
+
|
413
424
|
q = find_queue(name) || Bunny::Queue.new(self, name, opts)
|
414
425
|
|
415
426
|
register_queue(q)
|
416
427
|
end
|
417
428
|
|
429
|
+
# Declares a new client-named quorum queue.
|
430
|
+
#
|
431
|
+
# @param [String] name Queue name. Empty (server-generated) names are not supported by this method.
|
432
|
+
# @param [Hash] opts Queue properties and other options. Durability, exclusivity, auto-deletion options will be ignored.
|
433
|
+
#
|
434
|
+
# @option opts [Hash] :arguments ({}) Additional optional arguments (typically used by RabbitMQ extensions and plugins)
|
435
|
+
#
|
436
|
+
# @return [Bunny::Queue] Queue that was declared
|
437
|
+
# @see #durable_queue
|
438
|
+
# @see #queue
|
439
|
+
# @api public
|
440
|
+
def quorum_queue(name, opts = {})
|
441
|
+
throw ArgumentError.new("quorum queue name must not be nil") if name.nil?
|
442
|
+
throw ArgumentError.new("quorum queue name must not be empty (server-named QQs do not make sense)") if name.empty?
|
443
|
+
|
444
|
+
durable_queue(name, Bunny::Queue::Types::QUORUM, opts)
|
445
|
+
end
|
446
|
+
|
447
|
+
# Declares a new client-named stream (that Bunny can use as if it was a queue).
|
448
|
+
# Note that Bunny would still use AMQP 0-9-1 to perform operations on this "queue".
|
449
|
+
# To use stream-specific operations and to gain from stream protocol efficiency and partitioning,
|
450
|
+
# use a Ruby client for the RabbitMQ stream protocol.
|
451
|
+
#
|
452
|
+
# @param [String] name Stream name. Empty (server-generated) names are not supported by this method.
|
453
|
+
# @param [Hash] opts Queue properties and other options. Durability, exclusivity, auto-deletion options will be ignored.
|
454
|
+
#
|
455
|
+
# @option opts [Hash] :arguments ({}) Additional optional arguments (typically used by RabbitMQ extensions and plugins)
|
456
|
+
#
|
457
|
+
#
|
458
|
+
# @return [Bunny::Queue] Queue that was declared
|
459
|
+
# @see #durable_queue
|
460
|
+
# @see #queue
|
461
|
+
# @api public
|
462
|
+
def stream(name, opts = {})
|
463
|
+
throw ArgumentError.new("stream name must not be nil") if name.nil?
|
464
|
+
throw ArgumentError.new("stream name must not be empty (server-named QQs do not make sense)") if name.empty?
|
465
|
+
|
466
|
+
durable_queue(name, Bunny::Queue::Types::STREAM, opts)
|
467
|
+
end
|
468
|
+
|
469
|
+
# Declares a new server-named queue that is automatically deleted when the
|
470
|
+
# connection is closed.
|
471
|
+
#
|
472
|
+
# @param [String] name Queue name. Empty (server-generated) names are not supported by this method.
|
473
|
+
# @param [Hash] opts Queue properties and other options. Durability, exclusivity, auto-deletion options will be ignored.
|
474
|
+
#
|
475
|
+
# @option opts [Hash] :arguments ({}) Additional optional arguments (typically used by RabbitMQ extensions and plugins)
|
476
|
+
#
|
477
|
+
# @return [Bunny::Queue] Queue that was declared
|
478
|
+
# @see #queue
|
479
|
+
# @api public
|
480
|
+
def durable_queue(name, type = "classic", opts = {})
|
481
|
+
throw ArgumentError.new("queue name must not be nil") if name.nil?
|
482
|
+
throw ArgumentError.new("queue name must not be empty (server-named durable queues do not make sense)") if name.empty?
|
483
|
+
|
484
|
+
final_opts = opts.merge({
|
485
|
+
:type => type,
|
486
|
+
:durable => true,
|
487
|
+
# exclusive or auto-delete QQs do not make much sense
|
488
|
+
:exclusive => false,
|
489
|
+
:auto_delete => false
|
490
|
+
})
|
491
|
+
q = find_queue(name) || Bunny::Queue.new(self, name, final_opts)
|
492
|
+
|
493
|
+
register_queue(q)
|
494
|
+
end
|
495
|
+
|
418
496
|
# Declares a new server-named queue that is automatically deleted when the
|
419
497
|
# connection is closed.
|
420
498
|
#
|
@@ -643,7 +721,7 @@ module Bunny
|
|
643
721
|
|
644
722
|
@connection.send_frame(AMQ::Protocol::Basic::Qos.encode(@id, 0, count, global))
|
645
723
|
|
646
|
-
|
724
|
+
with_continuation_timeout do
|
647
725
|
@last_basic_qos_ok = wait_on_continuations
|
648
726
|
end
|
649
727
|
raise_if_continuation_resulted_in_a_channel_error!
|
@@ -664,7 +742,7 @@ module Bunny
|
|
664
742
|
raise_if_no_longer_open!
|
665
743
|
|
666
744
|
@connection.send_frame(AMQ::Protocol::Basic::Recover.encode(@id, requeue))
|
667
|
-
|
745
|
+
with_continuation_timeout do
|
668
746
|
@last_basic_recover_ok = wait_on_continuations
|
669
747
|
end
|
670
748
|
raise_if_continuation_resulted_in_a_channel_error!
|
@@ -871,7 +949,7 @@ module Bunny
|
|
871
949
|
arguments))
|
872
950
|
|
873
951
|
begin
|
874
|
-
|
952
|
+
with_continuation_timeout do
|
875
953
|
@last_basic_consume_ok = wait_on_continuations
|
876
954
|
end
|
877
955
|
rescue Exception => e
|
@@ -921,7 +999,7 @@ module Bunny
|
|
921
999
|
consumer.arguments))
|
922
1000
|
|
923
1001
|
begin
|
924
|
-
|
1002
|
+
with_continuation_timeout do
|
925
1003
|
@last_basic_consume_ok = wait_on_continuations
|
926
1004
|
end
|
927
1005
|
rescue Exception => e
|
@@ -956,7 +1034,7 @@ module Bunny
|
|
956
1034
|
def basic_cancel(consumer_tag)
|
957
1035
|
@connection.send_frame(AMQ::Protocol::Basic::Cancel.encode(@id, consumer_tag, false))
|
958
1036
|
|
959
|
-
|
1037
|
+
with_continuation_timeout do
|
960
1038
|
@last_basic_cancel_ok = wait_on_continuations
|
961
1039
|
end
|
962
1040
|
|
@@ -980,7 +1058,8 @@ module Bunny
|
|
980
1058
|
|
981
1059
|
# Declares a queue using queue.declare AMQP 0.9.1 method.
|
982
1060
|
#
|
983
|
-
# @param [String] name
|
1061
|
+
# @param [String] name The name of the queue or an empty string to let RabbitMQ generate a name.
|
1062
|
+
# Note that LF and CR characters will be stripped from the value.
|
984
1063
|
# @param [Hash] opts Queue properties
|
985
1064
|
#
|
986
1065
|
# @option opts [Boolean] durable (false) Should information about this queue be persisted to disk so that it
|
@@ -998,16 +1077,28 @@ module Bunny
|
|
998
1077
|
def queue_declare(name, opts = {})
|
999
1078
|
raise_if_no_longer_open!
|
1000
1079
|
|
1001
|
-
|
1002
|
-
|
1080
|
+
# strip trailing new line and carriage returns
|
1081
|
+
# just like RabbitMQ does
|
1082
|
+
safe_name = name.gsub(/[\r\n]/, "")
|
1083
|
+
@pending_queue_declare_name = safe_name
|
1084
|
+
@connection.send_frame(
|
1085
|
+
AMQ::Protocol::Queue::Declare.encode(@id,
|
1086
|
+
@pending_queue_declare_name,
|
1003
1087
|
opts.fetch(:passive, false),
|
1004
1088
|
opts.fetch(:durable, false),
|
1005
1089
|
opts.fetch(:exclusive, false),
|
1006
1090
|
opts.fetch(:auto_delete, false),
|
1007
1091
|
false,
|
1008
1092
|
opts[:arguments]))
|
1009
|
-
@last_queue_declare_ok = wait_on_continuations
|
1010
1093
|
|
1094
|
+
begin
|
1095
|
+
with_continuation_timeout do
|
1096
|
+
@last_queue_declare_ok = wait_on_continuations
|
1097
|
+
end
|
1098
|
+
ensure
|
1099
|
+
# clear pending continuation context if it belongs to us
|
1100
|
+
@pending_queue_declare_name = nil if @pending_queue_declare_name == safe_name
|
1101
|
+
end
|
1011
1102
|
raise_if_continuation_resulted_in_a_channel_error!
|
1012
1103
|
|
1013
1104
|
@last_queue_declare_ok
|
@@ -1032,7 +1123,7 @@ module Bunny
|
|
1032
1123
|
opts[:if_unused],
|
1033
1124
|
opts[:if_empty],
|
1034
1125
|
false))
|
1035
|
-
|
1126
|
+
with_continuation_timeout do
|
1036
1127
|
@last_queue_delete_ok = wait_on_continuations
|
1037
1128
|
end
|
1038
1129
|
raise_if_continuation_resulted_in_a_channel_error!
|
@@ -1052,7 +1143,7 @@ module Bunny
|
|
1052
1143
|
|
1053
1144
|
@connection.send_frame(AMQ::Protocol::Queue::Purge.encode(@id, name, false))
|
1054
1145
|
|
1055
|
-
|
1146
|
+
with_continuation_timeout do
|
1056
1147
|
@last_queue_purge_ok = wait_on_continuations
|
1057
1148
|
end
|
1058
1149
|
raise_if_continuation_resulted_in_a_channel_error!
|
@@ -1088,7 +1179,7 @@ module Bunny
|
|
1088
1179
|
(opts[:routing_key] || opts[:key]),
|
1089
1180
|
false,
|
1090
1181
|
opts[:arguments]))
|
1091
|
-
|
1182
|
+
with_continuation_timeout do
|
1092
1183
|
@last_queue_bind_ok = wait_on_continuations
|
1093
1184
|
end
|
1094
1185
|
|
@@ -1123,7 +1214,7 @@ module Bunny
|
|
1123
1214
|
exchange_name,
|
1124
1215
|
opts[:routing_key],
|
1125
1216
|
opts[:arguments]))
|
1126
|
-
|
1217
|
+
with_continuation_timeout do
|
1127
1218
|
@last_queue_unbind_ok = wait_on_continuations
|
1128
1219
|
end
|
1129
1220
|
|
@@ -1136,26 +1227,30 @@ module Bunny
|
|
1136
1227
|
|
1137
1228
|
# @group Exchange operations (exchange.*)
|
1138
1229
|
|
1139
|
-
# Declares a
|
1230
|
+
# Declares a exchange using exchange.declare AMQP 0.9.1 method.
|
1140
1231
|
#
|
1141
|
-
# @param [String] name
|
1232
|
+
# @param [String] name The name of the exchange. Note that LF and CR characters
|
1233
|
+
# will be stripped from the value.
|
1142
1234
|
# @param [String,Symbol] type Exchange type, e.g. :fanout or :topic
|
1143
1235
|
# @param [Hash] opts Exchange properties
|
1144
1236
|
#
|
1145
|
-
# @option opts [Boolean] durable (false) Should information about this
|
1237
|
+
# @option opts [Boolean] durable (false) Should information about this exchange be persisted to disk so that it
|
1146
1238
|
# can survive broker restarts? Typically set to true for long-lived exchanges.
|
1147
|
-
# @option opts [Boolean] auto_delete (false) Should this
|
1239
|
+
# @option opts [Boolean] auto_delete (false) Should this exchange be deleted when it is no longer used?
|
1148
1240
|
# @option opts [Boolean] passive (false) If true, exchange will be checked for existence. If it does not
|
1149
1241
|
# exist, {Bunny::NotFound} will be raised.
|
1150
1242
|
#
|
1151
1243
|
# @return [AMQ::Protocol::Exchange::DeclareOk] RabbitMQ response
|
1152
|
-
# @see http://rubybunny.info/articles/
|
1244
|
+
# @see http://rubybunny.info/articles/exchanges.html Exchanges and Publishing guide
|
1153
1245
|
# @api public
|
1154
1246
|
def exchange_declare(name, type, opts = {})
|
1155
1247
|
raise_if_no_longer_open!
|
1156
1248
|
|
1249
|
+
# strip trailing new line and carriage returns
|
1250
|
+
# just like RabbitMQ does
|
1251
|
+
safe_name = name.gsub(/[\r\n]/, "")
|
1157
1252
|
@connection.send_frame(AMQ::Protocol::Exchange::Declare.encode(@id,
|
1158
|
-
|
1253
|
+
safe_name,
|
1159
1254
|
type.to_s,
|
1160
1255
|
opts.fetch(:passive, false),
|
1161
1256
|
opts.fetch(:durable, false),
|
@@ -1163,7 +1258,7 @@ module Bunny
|
|
1163
1258
|
opts.fetch(:internal, false),
|
1164
1259
|
false, # nowait
|
1165
1260
|
opts[:arguments]))
|
1166
|
-
|
1261
|
+
with_continuation_timeout do
|
1167
1262
|
@last_exchange_declare_ok = wait_on_continuations
|
1168
1263
|
end
|
1169
1264
|
|
@@ -1188,7 +1283,7 @@ module Bunny
|
|
1188
1283
|
name,
|
1189
1284
|
opts[:if_unused],
|
1190
1285
|
false))
|
1191
|
-
|
1286
|
+
with_continuation_timeout do
|
1192
1287
|
@last_exchange_delete_ok = wait_on_continuations
|
1193
1288
|
end
|
1194
1289
|
|
@@ -1232,7 +1327,7 @@ module Bunny
|
|
1232
1327
|
opts[:routing_key],
|
1233
1328
|
false,
|
1234
1329
|
opts[:arguments]))
|
1235
|
-
|
1330
|
+
with_continuation_timeout do
|
1236
1331
|
@last_exchange_bind_ok = wait_on_continuations
|
1237
1332
|
end
|
1238
1333
|
|
@@ -1276,7 +1371,7 @@ module Bunny
|
|
1276
1371
|
opts[:routing_key],
|
1277
1372
|
false,
|
1278
1373
|
opts[:arguments]))
|
1279
|
-
|
1374
|
+
with_continuation_timeout do
|
1280
1375
|
@last_exchange_unbind_ok = wait_on_continuations
|
1281
1376
|
end
|
1282
1377
|
|
@@ -1304,7 +1399,7 @@ module Bunny
|
|
1304
1399
|
raise_if_no_longer_open!
|
1305
1400
|
|
1306
1401
|
@connection.send_frame(AMQ::Protocol::Channel::Flow.encode(@id, active))
|
1307
|
-
|
1402
|
+
with_continuation_timeout do
|
1308
1403
|
@last_channel_flow_ok = wait_on_continuations
|
1309
1404
|
end
|
1310
1405
|
raise_if_continuation_resulted_in_a_channel_error!
|
@@ -1325,7 +1420,7 @@ module Bunny
|
|
1325
1420
|
raise_if_no_longer_open!
|
1326
1421
|
|
1327
1422
|
@connection.send_frame(AMQ::Protocol::Tx::Select.encode(@id))
|
1328
|
-
|
1423
|
+
with_continuation_timeout do
|
1329
1424
|
@last_tx_select_ok = wait_on_continuations
|
1330
1425
|
end
|
1331
1426
|
raise_if_continuation_resulted_in_a_channel_error!
|
@@ -1341,7 +1436,7 @@ module Bunny
|
|
1341
1436
|
raise_if_no_longer_open!
|
1342
1437
|
|
1343
1438
|
@connection.send_frame(AMQ::Protocol::Tx::Commit.encode(@id))
|
1344
|
-
|
1439
|
+
with_continuation_timeout do
|
1345
1440
|
@last_tx_commit_ok = wait_on_continuations
|
1346
1441
|
end
|
1347
1442
|
raise_if_continuation_resulted_in_a_channel_error!
|
@@ -1356,7 +1451,7 @@ module Bunny
|
|
1356
1451
|
raise_if_no_longer_open!
|
1357
1452
|
|
1358
1453
|
@connection.send_frame(AMQ::Protocol::Tx::Rollback.encode(@id))
|
1359
|
-
|
1454
|
+
with_continuation_timeout do
|
1360
1455
|
@last_tx_rollback_ok = wait_on_continuations
|
1361
1456
|
end
|
1362
1457
|
raise_if_continuation_resulted_in_a_channel_error!
|
@@ -1403,7 +1498,7 @@ module Bunny
|
|
1403
1498
|
@confirms_callback = callback
|
1404
1499
|
|
1405
1500
|
@connection.send_frame(AMQ::Protocol::Confirm::Select.encode(@id, false))
|
1406
|
-
|
1501
|
+
with_continuation_timeout do
|
1407
1502
|
@last_confirm_select_ok = wait_on_continuations
|
1408
1503
|
end
|
1409
1504
|
raise_if_continuation_resulted_in_a_channel_error!
|
@@ -1501,12 +1596,15 @@ module Bunny
|
|
1501
1596
|
|
1502
1597
|
# Recovers publisher confirms mode. Used by the Automatic Network Failure
|
1503
1598
|
# Recovery feature.
|
1599
|
+
# Set the offset to the previous publish sequence index as the protocol will reset the index to after recovery.
|
1504
1600
|
#
|
1505
1601
|
# @api plugin
|
1506
1602
|
def recover_confirm_mode
|
1507
1603
|
if using_publisher_confirmations?
|
1508
|
-
@
|
1509
|
-
|
1604
|
+
@unconfirmed_set_mutex.synchronize do
|
1605
|
+
@unconfirmed_set.clear
|
1606
|
+
@delivery_tag_offset = @next_publish_seq_no - 1
|
1607
|
+
end
|
1510
1608
|
confirm_select(@confirms_callback)
|
1511
1609
|
end
|
1512
1610
|
end
|
@@ -1575,7 +1673,11 @@ module Bunny
|
|
1575
1673
|
|
1576
1674
|
# @return [String] Brief human-readable representation of the channel
|
1577
1675
|
def to_s
|
1578
|
-
"#<#{self.class.name}:#{object_id} @id=#{self.number} @connection=#{@connection.to_s}>"
|
1676
|
+
"#<#{self.class.name}:#{object_id} @id=#{self.number} @connection=#{@connection.to_s} @open=#{open?}>"
|
1677
|
+
end
|
1678
|
+
|
1679
|
+
def inspect
|
1680
|
+
to_s
|
1579
1681
|
end
|
1580
1682
|
|
1581
1683
|
|
@@ -1583,6 +1685,11 @@ module Bunny
|
|
1583
1685
|
# Implementation
|
1584
1686
|
#
|
1585
1687
|
|
1688
|
+
# @private
|
1689
|
+
def with_continuation_timeout(&block)
|
1690
|
+
Bunny::Timeout.timeout(wait_on_continuations_timeout, ClientTimeout, &block)
|
1691
|
+
end
|
1692
|
+
|
1586
1693
|
# @private
|
1587
1694
|
def register_consumer(consumer_tag, consumer)
|
1588
1695
|
@consumer_mutex.synchronize do
|
@@ -1606,12 +1713,33 @@ module Bunny
|
|
1606
1713
|
end
|
1607
1714
|
end
|
1608
1715
|
|
1716
|
+
# @private
|
1717
|
+
def pending_server_named_queue_declaration?
|
1718
|
+
@pending_queue_declare_name && @pending_queue_declare_name.empty?
|
1719
|
+
end
|
1720
|
+
|
1721
|
+
# @private
|
1722
|
+
def can_accept_queue_declare_ok?(method)
|
1723
|
+
@pending_queue_declare_name == method.queue ||
|
1724
|
+
pending_server_named_queue_declaration?
|
1725
|
+
end
|
1726
|
+
|
1609
1727
|
# @private
|
1610
1728
|
def handle_method(method)
|
1611
1729
|
@logger.debug { "Channel#handle_frame on channel #{@id}: #{method.inspect}" }
|
1612
1730
|
case method
|
1613
1731
|
when AMQ::Protocol::Queue::DeclareOk then
|
1614
|
-
|
1732
|
+
# safeguard against late arrivals of responses and
|
1733
|
+
# so on, see ruby-amqp/bunny#558
|
1734
|
+
if can_accept_queue_declare_ok?(method)
|
1735
|
+
@continuations.push(method)
|
1736
|
+
else
|
1737
|
+
if !pending_server_named_queue_declaration?
|
1738
|
+
# this response is for an outdated/overwritten
|
1739
|
+
# queue.declare, drop it
|
1740
|
+
@logger.warn "Received a queue.declare-ok response for a mismatching queue (#{method.queue} instead of #{@pending_queue_declare_name}) on channel #{@id}, possibly due to concurrent channel use or a timeout, ignoring it"
|
1741
|
+
end
|
1742
|
+
end
|
1615
1743
|
when AMQ::Protocol::Queue::DeleteOk then
|
1616
1744
|
@continuations.push(method)
|
1617
1745
|
when AMQ::Protocol::Queue::PurgeOk then
|
@@ -1732,14 +1860,16 @@ module Bunny
|
|
1732
1860
|
end
|
1733
1861
|
end
|
1734
1862
|
|
1863
|
+
# Handle delivery tag offset calculations to keep the the delivery tag monotonic after a reset
|
1864
|
+
# due to automatic network failure recovery. @unconfirmed_set contains indices already offsetted.
|
1735
1865
|
# @private
|
1736
1866
|
def handle_ack_or_nack(delivery_tag_before_offset, multiple, nack)
|
1737
|
-
delivery_tag = delivery_tag_before_offset + @delivery_tag_offset
|
1738
|
-
confirmed_range_start = multiple ? @delivery_tag_offset + 1 : delivery_tag
|
1739
|
-
confirmed_range_end = delivery_tag
|
1740
|
-
confirmed_range = (confirmed_range_start..confirmed_range_end)
|
1741
|
-
|
1742
1867
|
@unconfirmed_set_mutex.synchronize do
|
1868
|
+
delivery_tag = delivery_tag_before_offset + @delivery_tag_offset
|
1869
|
+
confirmed_range_start = multiple ? @unconfirmed_set.min : delivery_tag
|
1870
|
+
confirmed_range_end = delivery_tag
|
1871
|
+
confirmed_range = (confirmed_range_start..confirmed_range_end)
|
1872
|
+
|
1743
1873
|
if nack
|
1744
1874
|
@nacked_set.merge(@unconfirmed_set & confirmed_range)
|
1745
1875
|
end
|
@@ -1940,7 +2070,13 @@ module Bunny
|
|
1940
2070
|
|
1941
2071
|
# @private
|
1942
2072
|
def raise_if_no_longer_open!
|
1943
|
-
|
2073
|
+
if closed?
|
2074
|
+
if @last_channel_error
|
2075
|
+
raise ChannelAlreadyClosed.new("cannot use a closed channel! Channel id: #{@id}, closed due to a server-reported channel error: #{@last_channel_error.message}", self)
|
2076
|
+
else
|
2077
|
+
raise ChannelAlreadyClosed.new("cannot use a closed channel! Channel id: #{@id}", self)
|
2078
|
+
end
|
2079
|
+
end
|
1944
2080
|
end
|
1945
2081
|
|
1946
2082
|
# @private
|
@@ -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
|
data/lib/bunny/consumer.rb
CHANGED
@@ -86,12 +86,12 @@ module Bunny
|
|
86
86
|
|
87
87
|
# @return [String] More detailed human-readable string representation of this consumer
|
88
88
|
def inspect
|
89
|
-
"#<#{self.class.name}:#{object_id} @channel_id=#{@channel.number} @queue=#{self.queue_name}
|
89
|
+
"#<#{self.class.name}:#{object_id} @channel_id=#{@channel.number} @queue=#{self.queue_name} @consumer_tag=#{@consumer_tag} @exclusive=#{@exclusive} @no_ack=#{@no_ack}>"
|
90
90
|
end
|
91
91
|
|
92
92
|
# @return [String] Brief human-readable string representation of this consumer
|
93
93
|
def to_s
|
94
|
-
"#<#{self.class.name}:#{object_id} @channel_id=#{@channel.number} @queue=#{self.queue_name}
|
94
|
+
"#<#{self.class.name}:#{object_id} @channel_id=#{@channel.number} @queue=#{self.queue_name} @consumer_tag=#{@consumer_tag}>"
|
95
95
|
end
|
96
96
|
|
97
97
|
# @return [Boolean] true if this consumer uses automatic acknowledgement mode
|
@@ -25,6 +25,7 @@ module Bunny
|
|
25
25
|
@shutdown_conditional = ::ConditionVariable.new
|
26
26
|
@queue = ::Queue.new
|
27
27
|
@paused = false
|
28
|
+
@running = false
|
28
29
|
end
|
29
30
|
|
30
31
|
|
@@ -69,7 +70,7 @@ module Bunny
|
|
69
70
|
return if !(wait_for_workers && @shutdown_timeout && was_running)
|
70
71
|
|
71
72
|
@shutdown_mutex.synchronize do
|
72
|
-
@shutdown_conditional.wait(@shutdown_mutex, @shutdown_timeout)
|
73
|
+
@shutdown_conditional.wait(@shutdown_mutex, @shutdown_timeout) if busy?
|
73
74
|
end
|
74
75
|
end
|
75
76
|
|
data/lib/bunny/cruby/socket.rb
CHANGED
@@ -32,6 +32,9 @@ module Bunny
|
|
32
32
|
socket.setsockopt(::Socket::IPPROTO_TCP, ::Socket::TCP_NODELAY, true)
|
33
33
|
end
|
34
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
|
37
|
+
end
|
35
38
|
socket.extend self
|
36
39
|
socket.options = { :host => host, :port => port }.merge(options)
|
37
40
|
socket
|
@@ -24,6 +24,11 @@ module Bunny
|
|
24
24
|
[Errno::EAGAIN, Errno::EWOULDBLOCK, IO::WaitWritable]
|
25
25
|
end
|
26
26
|
|
27
|
+
def initialize(*args)
|
28
|
+
super
|
29
|
+
@__bunny_socket_eof_flag__ = false
|
30
|
+
end
|
31
|
+
|
27
32
|
# Reads given number of bytes with an optional timeout
|
28
33
|
#
|
29
34
|
# @param [Integer] count How many bytes to read
|
@@ -107,7 +112,7 @@ module Bunny
|
|
107
112
|
end
|
108
113
|
|
109
114
|
end
|
110
|
-
rescue LoadError
|
115
|
+
rescue LoadError
|
111
116
|
puts "Could not load OpenSSL"
|
112
117
|
end
|
113
118
|
end
|
data/lib/bunny/delivery_info.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
|
|
@@ -63,7 +64,7 @@ module Bunny
|
|
63
64
|
|
64
65
|
if now > (@last_activity_time + @interval)
|
65
66
|
@logger.debug { "Sending a heartbeat, last activity time: #{@last_activity_time}, interval (s): #{@interval}" }
|
66
|
-
@transport.write_without_timeout(AMQ::Protocol::HeartbeatFrame.encode)
|
67
|
+
@transport.write_without_timeout(AMQ::Protocol::HeartbeatFrame.encode, true)
|
67
68
|
end
|
68
69
|
end
|
69
70
|
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
|