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