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