bunny 1.2.0 → 1.2.1
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 +4 -4
- data/ChangeLog.md +17 -0
- data/lib/bunny/channel.rb +32 -21
- data/lib/bunny/session.rb +5 -1
- data/lib/bunny/version.rb +1 -1
- data/spec/higher_level_api/integration/connection_recovery_spec.rb +234 -0
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c8f1c8052f218b6d4ed95579a93e03ee9014fea5
|
4
|
+
data.tar.gz: 739d9b25a80d0c6063124229fe8226fe45390ed3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0fe50e8b79c8611edf5f6b3f152b21680fdcb9790bf73126a2c3e4e2bbc38d485b26cef1edf0bde99eca2e8d34c784776396cd4cf8a26829b53ca7974de45430
|
7
|
+
data.tar.gz: 2cb6bf110f3c9508eb055e37c2aebac6ff0915e6d89e014934738b9671041e6b34a9af13aca165d057d296a73efd6f2497efaaa4c0049726b9a362cf31c26e35
|
data/ChangeLog.md
CHANGED
@@ -1,3 +1,20 @@
|
|
1
|
+
## Changes between Bunny 1.2.0 and 1.2.1
|
2
|
+
|
3
|
+
### Better Synchronization for Publisher Confirms
|
4
|
+
|
5
|
+
Publisher confirms implementation now synchronizes unconfirmed
|
6
|
+
set better.
|
7
|
+
|
8
|
+
Contributed by Nicolas Viennot.
|
9
|
+
|
10
|
+
### Channel Allocation After Recovery
|
11
|
+
|
12
|
+
Channel id allocator is no longer reset after recovery
|
13
|
+
if there are channels open. Makes it possible to open channels
|
14
|
+
on a recovered connection (in addition to the channels
|
15
|
+
it already had).
|
16
|
+
|
17
|
+
|
1
18
|
## Changes between Bunny 1.1.0 and 1.2.0
|
2
19
|
|
3
20
|
### :key Supported in Bunny::Channel#queue_bind
|
data/lib/bunny/channel.rb
CHANGED
@@ -157,6 +157,9 @@ module Bunny
|
|
157
157
|
# @return [Hash<String, Bunny::Consumer>] Consumer instances declared on this channel
|
158
158
|
attr_reader :consumers
|
159
159
|
|
160
|
+
# @return [Integer] active basic.qos prefetch value
|
161
|
+
attr_reader :prefetch_count
|
162
|
+
|
160
163
|
DEFAULT_CONTENT_TYPE = "application/octet-stream".freeze
|
161
164
|
SHORTSTR_LIMIT = 255
|
162
165
|
|
@@ -412,8 +415,8 @@ module Bunny
|
|
412
415
|
# @see http://rubybunny.info/articles/exchanges.html Exchanges and Publishing guide
|
413
416
|
# @see http://rubybunny.info/articles/queues.html Queues and Consumers guide
|
414
417
|
# @api public
|
415
|
-
def prefetch(
|
416
|
-
self.basic_qos(
|
418
|
+
def prefetch(count)
|
419
|
+
self.basic_qos(count, false)
|
417
420
|
end
|
418
421
|
|
419
422
|
# Flow control. When set to false, RabbitMQ will stop delivering messages on this
|
@@ -536,8 +539,10 @@ module Bunny
|
|
536
539
|
opts[:priority] ||= 0
|
537
540
|
|
538
541
|
if @next_publish_seq_no > 0
|
539
|
-
@
|
540
|
-
|
542
|
+
@unconfirmed_set_mutex.synchronize do
|
543
|
+
@unconfirmed_set.add(@next_publish_seq_no)
|
544
|
+
@next_publish_seq_no += 1
|
545
|
+
end
|
541
546
|
end
|
542
547
|
|
543
548
|
frames = AMQ::Protocol::Basic::Publish.encode(@id,
|
@@ -604,18 +609,18 @@ module Bunny
|
|
604
609
|
# @see Bunny::Channel#prefetch
|
605
610
|
# @see http://rubybunny.info/articles/queues.html Queues and Consumers guide
|
606
611
|
# @api public
|
607
|
-
def basic_qos(
|
608
|
-
raise ArgumentError.new("prefetch count must be a positive integer, given: #{prefetch_count}") if
|
612
|
+
def basic_qos(count, global = false)
|
613
|
+
raise ArgumentError.new("prefetch count must be a positive integer, given: #{prefetch_count}") if count < 0
|
609
614
|
raise_if_no_longer_open!
|
610
615
|
|
611
|
-
@connection.send_frame(AMQ::Protocol::Basic::Qos.encode(@id, 0,
|
616
|
+
@connection.send_frame(AMQ::Protocol::Basic::Qos.encode(@id, 0, count, global))
|
612
617
|
|
613
618
|
Bunny::Timeout.timeout(read_write_timeout, ClientTimeout) do
|
614
619
|
@last_basic_qos_ok = wait_on_continuations
|
615
620
|
end
|
616
621
|
raise_if_continuation_resulted_in_a_channel_error!
|
617
622
|
|
618
|
-
@prefetch_count =
|
623
|
+
@prefetch_count = count
|
619
624
|
|
620
625
|
@last_basic_qos_ok
|
621
626
|
end
|
@@ -1321,6 +1326,11 @@ module Bunny
|
|
1321
1326
|
@last_tx_rollback_ok
|
1322
1327
|
end
|
1323
1328
|
|
1329
|
+
# @return [Boolean] true if this channel has transactions enabled
|
1330
|
+
def using_tx?
|
1331
|
+
!!@tx_mode
|
1332
|
+
end
|
1333
|
+
|
1324
1334
|
# @endgroup
|
1325
1335
|
|
1326
1336
|
|
@@ -1332,6 +1342,7 @@ module Bunny
|
|
1332
1342
|
def using_publisher_confirmations?
|
1333
1343
|
@next_publish_seq_no > 0
|
1334
1344
|
end
|
1345
|
+
alias using_publisher_confirms? using_publisher_confirmations?
|
1335
1346
|
|
1336
1347
|
# Enables publisher confirms for the channel.
|
1337
1348
|
# @return [AMQ::Protocol::Confirm::SelectOk] RabbitMQ response
|
@@ -1681,23 +1692,23 @@ module Bunny
|
|
1681
1692
|
|
1682
1693
|
# @private
|
1683
1694
|
def handle_ack_or_nack(delivery_tag, multiple, nack)
|
1684
|
-
|
1685
|
-
|
1695
|
+
@unconfirmed_set_mutex.synchronize do
|
1696
|
+
if nack
|
1697
|
+
cloned_set = @unconfirmed_set.clone
|
1698
|
+
if multiple
|
1699
|
+
cloned_set.keep_if { |i| i <= delivery_tag }
|
1700
|
+
@nacked_set.merge(cloned_set)
|
1701
|
+
else
|
1702
|
+
@nacked_set.add(delivery_tag)
|
1703
|
+
end
|
1704
|
+
end
|
1705
|
+
|
1686
1706
|
if multiple
|
1687
|
-
|
1688
|
-
@nacked_set.merge(cloned_set)
|
1707
|
+
@unconfirmed_set.delete_if { |i| i <= delivery_tag }
|
1689
1708
|
else
|
1690
|
-
@
|
1709
|
+
@unconfirmed_set.delete(delivery_tag)
|
1691
1710
|
end
|
1692
|
-
end
|
1693
|
-
|
1694
|
-
if multiple
|
1695
|
-
@unconfirmed_set.delete_if { |i| i <= delivery_tag }
|
1696
|
-
else
|
1697
|
-
@unconfirmed_set.delete(delivery_tag)
|
1698
|
-
end
|
1699
1711
|
|
1700
|
-
@unconfirmed_set_mutex.synchronize do
|
1701
1712
|
@only_acks_received = (@only_acks_received && !nack)
|
1702
1713
|
|
1703
1714
|
@confirms_continuations.push(true) if @unconfirmed_set.empty?
|
data/lib/bunny/session.rb
CHANGED
@@ -975,7 +975,11 @@ module Bunny
|
|
975
975
|
@logger.debug "Heartbeat interval negotiation: client = #{@client_heartbeat}, server = #{connection_tune.heartbeat}, result = #{@heartbeat}"
|
976
976
|
@logger.info "Heartbeat interval used (in seconds): #{@heartbeat}"
|
977
977
|
|
978
|
-
|
978
|
+
# if there are existing channels we've just recovered from
|
979
|
+
# a network failure and need to fix the allocated set. See issue 205. MK.
|
980
|
+
if @channels.empty?
|
981
|
+
@channel_id_allocator = ChannelIdAllocator.new(@channel_max)
|
982
|
+
end
|
979
983
|
|
980
984
|
@transport.send_frame(AMQ::Protocol::Connection::TuneOk.encode(@channel_max, @frame_max, @heartbeat))
|
981
985
|
@logger.debug "Sent connection.tune-ok with heartbeat interval = #{@heartbeat}, frame_max = #{@frame_max}, channel_max = #{@channel_max}"
|
data/lib/bunny/version.rb
CHANGED
@@ -0,0 +1,234 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require "rabbitmq/http/client"
|
3
|
+
|
4
|
+
unless ENV["CI"]
|
5
|
+
describe "Connection recovery" do
|
6
|
+
let(:connection) { }
|
7
|
+
let(:http_client) { RabbitMQ::HTTP::Client.new("http://127.0.0.1:15672") }
|
8
|
+
|
9
|
+
def close_all_connections!
|
10
|
+
http_client.list_connections.each do |conn_info|
|
11
|
+
http_client.close_connection(conn_info.name)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def wait_for_recovery
|
16
|
+
sleep 0.7
|
17
|
+
end
|
18
|
+
|
19
|
+
def with_open(c = Bunny.new(:network_recovery_interval => 0.2, :recover_from_connection_close => true), &block)
|
20
|
+
begin
|
21
|
+
c.start
|
22
|
+
block.call(c)
|
23
|
+
ensure
|
24
|
+
c.close
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def ensure_queue_recovery(ch, q)
|
29
|
+
q.purge
|
30
|
+
x = ch.default_exchange
|
31
|
+
x.publish("msg", :routing_key => q.name)
|
32
|
+
sleep 0.2
|
33
|
+
q.message_count.should == 1
|
34
|
+
q.purge
|
35
|
+
end
|
36
|
+
|
37
|
+
def ensure_queue_binding_recovery(x, q, routing_key = "")
|
38
|
+
q.purge
|
39
|
+
x.publish("msg", :routing_key => routing_key)
|
40
|
+
sleep 0.2
|
41
|
+
q.message_count.should == 1
|
42
|
+
q.purge
|
43
|
+
end
|
44
|
+
|
45
|
+
def ensure_exchange_binding_recovery(ch, source, destination, routing_key = "")
|
46
|
+
q = ch.queue("", :exclusive => true)
|
47
|
+
q.bind(destination, :routing_key => routing_key)
|
48
|
+
|
49
|
+
source.publish("msg", :routing_key => routing_key)
|
50
|
+
q.message_count.should == 1
|
51
|
+
q.delete
|
52
|
+
end
|
53
|
+
|
54
|
+
#
|
55
|
+
# Examples
|
56
|
+
#
|
57
|
+
|
58
|
+
it "reconnects after grace period" do
|
59
|
+
with_open do |c|
|
60
|
+
close_all_connections!
|
61
|
+
sleep 0.1
|
62
|
+
c.should_not be_open
|
63
|
+
|
64
|
+
wait_for_recovery
|
65
|
+
c.should be_open
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
it "recovers channel" do
|
70
|
+
with_open do |c|
|
71
|
+
ch1 = c.create_channel
|
72
|
+
ch2 = c.create_channel
|
73
|
+
close_all_connections!
|
74
|
+
sleep 0.1
|
75
|
+
c.should_not be_open
|
76
|
+
|
77
|
+
wait_for_recovery
|
78
|
+
ch1.should be_open
|
79
|
+
ch2.should be_open
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
it "recovers basic.qos prefetch setting" do
|
84
|
+
with_open do |c|
|
85
|
+
ch = c.create_channel
|
86
|
+
ch.prefetch(11)
|
87
|
+
ch.prefetch_count.should == 11
|
88
|
+
close_all_connections!
|
89
|
+
sleep 0.1
|
90
|
+
c.should_not be_open
|
91
|
+
|
92
|
+
wait_for_recovery
|
93
|
+
ch.should be_open
|
94
|
+
ch.prefetch_count.should == 11
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
|
99
|
+
it "recovers publisher confirms setting" do
|
100
|
+
with_open do |c|
|
101
|
+
ch = c.create_channel
|
102
|
+
ch.confirm_select
|
103
|
+
ch.should be_using_publisher_confirms
|
104
|
+
close_all_connections!
|
105
|
+
sleep 0.1
|
106
|
+
c.should_not be_open
|
107
|
+
|
108
|
+
wait_for_recovery
|
109
|
+
ch.should be_open
|
110
|
+
ch.should be_using_publisher_confirms
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
it "recovers transactionality setting" do
|
115
|
+
with_open do |c|
|
116
|
+
ch = c.create_channel
|
117
|
+
ch.tx_select
|
118
|
+
ch.should be_using_tx
|
119
|
+
close_all_connections!
|
120
|
+
sleep 0.1
|
121
|
+
c.should_not be_open
|
122
|
+
|
123
|
+
wait_for_recovery
|
124
|
+
ch.should be_open
|
125
|
+
ch.should be_using_tx
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
it "recovers client-named queues" do
|
130
|
+
with_open do |c|
|
131
|
+
ch = c.create_channel
|
132
|
+
q = ch.queue("bunny.tests.recovery.client-named#{rand}")
|
133
|
+
close_all_connections!
|
134
|
+
sleep 0.1
|
135
|
+
c.should_not be_open
|
136
|
+
|
137
|
+
wait_for_recovery
|
138
|
+
ch.should be_open
|
139
|
+
ensure_queue_recovery(ch, q)
|
140
|
+
q.delete
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
|
145
|
+
it "recovers server-named queues" do
|
146
|
+
with_open do |c|
|
147
|
+
ch = c.create_channel
|
148
|
+
q = ch.queue("", :exclusive => true)
|
149
|
+
close_all_connections!
|
150
|
+
sleep 0.1
|
151
|
+
c.should_not be_open
|
152
|
+
|
153
|
+
wait_for_recovery
|
154
|
+
ch.should be_open
|
155
|
+
ensure_queue_recovery(ch, q)
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
it "recovers queue bindings" do
|
160
|
+
with_open do |c|
|
161
|
+
ch = c.create_channel
|
162
|
+
x = ch.fanout("amq.fanout")
|
163
|
+
q = ch.queue("", :exclusive => true)
|
164
|
+
q.bind(x)
|
165
|
+
close_all_connections!
|
166
|
+
sleep 0.1
|
167
|
+
c.should_not be_open
|
168
|
+
|
169
|
+
wait_for_recovery
|
170
|
+
ch.should be_open
|
171
|
+
ensure_queue_binding_recovery(x, q)
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
it "recovers exchange bindings" do
|
176
|
+
with_open do |c|
|
177
|
+
ch = c.create_channel
|
178
|
+
x = ch.fanout("amq.fanout")
|
179
|
+
x2 = ch.fanout("bunny.tests.recovery.fanout")
|
180
|
+
x2.bind(x)
|
181
|
+
close_all_connections!
|
182
|
+
sleep 0.1
|
183
|
+
c.should_not be_open
|
184
|
+
|
185
|
+
wait_for_recovery
|
186
|
+
ch.should be_open
|
187
|
+
ensure_exchange_binding_recovery(ch, x, x2)
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
it "recovers allocated channel ids" do
|
192
|
+
with_open do |c|
|
193
|
+
q = "queue#{Time.now.to_i}"
|
194
|
+
10.times { c.create_channel }
|
195
|
+
c.queue_exists?(q).should be_false
|
196
|
+
close_all_connections!
|
197
|
+
sleep 0.1
|
198
|
+
c.should_not be_open
|
199
|
+
|
200
|
+
wait_for_recovery
|
201
|
+
c.queue_exists?(q).should be_false
|
202
|
+
# make sure the connection isn't closed shortly after
|
203
|
+
# due to "second 'channel.open' seen". MK.
|
204
|
+
c.should be_open
|
205
|
+
sleep 0.1
|
206
|
+
c.should be_open
|
207
|
+
sleep 0.1
|
208
|
+
c.should be_open
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
it "recovers consumer" do
|
213
|
+
with_open do |c|
|
214
|
+
delivered = false
|
215
|
+
|
216
|
+
ch = c.create_channel
|
217
|
+
q = ch.queue("", :exclusive => true)
|
218
|
+
q.subscribe do |_, _, _|
|
219
|
+
delivered = true
|
220
|
+
end
|
221
|
+
close_all_connections!
|
222
|
+
sleep 0.1
|
223
|
+
c.should_not be_open
|
224
|
+
|
225
|
+
wait_for_recovery
|
226
|
+
ch.should be_open
|
227
|
+
|
228
|
+
q.publish("")
|
229
|
+
sleep 0.5
|
230
|
+
expect(delivered).to be_true
|
231
|
+
end
|
232
|
+
end
|
233
|
+
end
|
234
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bunny
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.2.
|
4
|
+
version: 1.2.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Chris Duncan
|
@@ -12,7 +12,7 @@ authors:
|
|
12
12
|
autorequire:
|
13
13
|
bindir: bin
|
14
14
|
cert_chain: []
|
15
|
-
date: 2014-04-
|
15
|
+
date: 2014-04-11 00:00:00.000000000 Z
|
16
16
|
dependencies:
|
17
17
|
- !ruby/object:Gem::Dependency
|
18
18
|
name: amq-protocol
|
@@ -152,6 +152,7 @@ files:
|
|
152
152
|
- spec/higher_level_api/integration/channel_close_spec.rb
|
153
153
|
- spec/higher_level_api/integration/channel_open_spec.rb
|
154
154
|
- spec/higher_level_api/integration/confirm_select_spec.rb
|
155
|
+
- spec/higher_level_api/integration/connection_recovery_spec.rb
|
155
156
|
- spec/higher_level_api/integration/connection_spec.rb
|
156
157
|
- spec/higher_level_api/integration/connection_stop_spec.rb
|
157
158
|
- spec/higher_level_api/integration/consistent_hash_exchange_spec.rb
|
@@ -248,6 +249,7 @@ test_files:
|
|
248
249
|
- spec/higher_level_api/integration/channel_close_spec.rb
|
249
250
|
- spec/higher_level_api/integration/channel_open_spec.rb
|
250
251
|
- spec/higher_level_api/integration/confirm_select_spec.rb
|
252
|
+
- spec/higher_level_api/integration/connection_recovery_spec.rb
|
251
253
|
- spec/higher_level_api/integration/connection_spec.rb
|
252
254
|
- spec/higher_level_api/integration/connection_stop_spec.rb
|
253
255
|
- spec/higher_level_api/integration/consistent_hash_exchange_spec.rb
|