bunny 1.3.1 → 1.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/ChangeLog.md +14 -2
- data/Gemfile +1 -1
- data/README.md +2 -2
- data/lib/bunny/channel.rb +40 -23
- data/lib/bunny/version.rb +1 -1
- data/spec/higher_level_api/integration/publisher_confirms_spec.rb +90 -41
- data/spec/issues/issue224_spec.rb +40 -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: f1cf8263f0250d0bf8f2816bf1aaad837c5505eb
|
4
|
+
data.tar.gz: bafa849e30666c22ff3574507567d27d7859f89b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a5e14b69c7a128c20e95e2850e80d5517f27f1d93068468ff0058cf9c041a1a8f243ec9c67119580e55dcedb9c6370d59eea15a38be2384b38678fee4307c591
|
7
|
+
data.tar.gz: 849e7085e43ef4b3859940f492472c5058ffffdd0d18d1cdb1946fcf39b7b7761d7f2b4150f05dac6c7b39aa7e2a0e295d8a267d397d3b74815e9b97b4ab881f
|
data/ChangeLog.md
CHANGED
@@ -1,8 +1,20 @@
|
|
1
|
-
## Changes between Bunny 1.3.0 and 1.
|
1
|
+
## Changes between Bunny 1.3.0 and 1.4.0
|
2
|
+
|
3
|
+
### Channel#wait_for_confirms Returns Immediately If All Publishes Confirmed
|
4
|
+
|
5
|
+
Contributed by Matt Campbell.
|
6
|
+
|
7
|
+
### Publisher Confirms is In Sync After Recovery
|
8
|
+
|
9
|
+
When a connection is recovered, the sequence counter resets on the
|
10
|
+
broker, but not the client. To keep things in sync the client must store a confirmation
|
11
|
+
offset after a recovery.
|
12
|
+
|
13
|
+
Contributed by Devin Christensen.
|
2
14
|
|
3
15
|
### NoMethodError on Thread During Shutdown
|
4
16
|
|
5
|
-
During abnormal termination, `Bunny::Session` no longer tries
|
17
|
+
During abnormal termination, `Bunny::Session#close` no longer tries
|
6
18
|
to call the non-existent `terminate_with` method on its origin
|
7
19
|
thread.
|
8
20
|
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -95,7 +95,7 @@ gem install bunny
|
|
95
95
|
To use Bunny in a project managed with Bundler:
|
96
96
|
|
97
97
|
``` ruby
|
98
|
-
gem "bunny", "~> 1.1
|
98
|
+
gem "bunny", "~> 1.3.1"
|
99
99
|
```
|
100
100
|
|
101
101
|
|
@@ -162,7 +162,7 @@ Other documentation guides are available at [rubybunny.info](http://rubybunny.in
|
|
162
162
|
### Mailing List
|
163
163
|
|
164
164
|
[Bunny has a mailing list](http://groups.google.com/group/ruby-amqp). We encourage you
|
165
|
-
to also join the [
|
165
|
+
to also join the [RabbitMQ mailing list](https://groups.google.com/forum/#!forum/rabbitmq-users) mailing list. Feel free to ask any questions that you may have.
|
166
166
|
|
167
167
|
|
168
168
|
### IRC
|
data/lib/bunny/channel.rb
CHANGED
@@ -195,6 +195,7 @@ module Bunny
|
|
195
195
|
@threads_waiting_on_basic_get_continuations = Set.new
|
196
196
|
|
197
197
|
@next_publish_seq_no = 0
|
198
|
+
@delivery_tag_offset = 0
|
198
199
|
|
199
200
|
@recoveries_counter = Bunny::Concurrent::AtomicFixnum.new(0)
|
200
201
|
@uncaught_exception_handler = Proc.new do |e, consumer|
|
@@ -1359,6 +1360,7 @@ module Bunny
|
|
1359
1360
|
@unconfirmed_set = Set.new
|
1360
1361
|
@nacked_set = Set.new
|
1361
1362
|
@next_publish_seq_no = 1
|
1363
|
+
@only_acks_received = true
|
1362
1364
|
end
|
1363
1365
|
|
1364
1366
|
@confirms_callback = callback
|
@@ -1373,19 +1375,18 @@ module Bunny
|
|
1373
1375
|
end
|
1374
1376
|
|
1375
1377
|
# Blocks calling thread until confirms are received for all
|
1376
|
-
# currently unacknowledged published messages.
|
1378
|
+
# currently unacknowledged published messages. Returns immediately
|
1379
|
+
# if there are no outstanding confirms.
|
1377
1380
|
#
|
1378
|
-
# @return [Boolean] true if all messages were acknowledged positively, false otherwise
|
1381
|
+
# @return [Boolean] true if all messages were acknowledged positively since the last time this method was called, false otherwise
|
1379
1382
|
# @see #confirm_select
|
1380
1383
|
# @see #unconfirmed_set
|
1381
1384
|
# @see #nacked_set
|
1382
1385
|
# @see http://rubybunny.info/articles/extensions.html RabbitMQ Extensions guide
|
1383
1386
|
# @api public
|
1384
1387
|
def wait_for_confirms
|
1385
|
-
@only_acks_received = true
|
1386
1388
|
wait_on_confirms_continuations
|
1387
|
-
|
1388
|
-
@only_acks_received
|
1389
|
+
read_and_reset_only_acks_received
|
1389
1390
|
end
|
1390
1391
|
|
1391
1392
|
# @endgroup
|
@@ -1467,7 +1468,10 @@ module Bunny
|
|
1467
1468
|
#
|
1468
1469
|
# @api plugin
|
1469
1470
|
def recover_confirm_mode
|
1470
|
-
|
1471
|
+
if using_publisher_confirmations?
|
1472
|
+
@delivery_tag_offset = @next_publish_seq_no - 1
|
1473
|
+
confirm_select(@confirms_callback)
|
1474
|
+
end
|
1471
1475
|
end
|
1472
1476
|
|
1473
1477
|
# Recovers transaction mode. Used by the Automatic Network Failure
|
@@ -1691,28 +1695,26 @@ module Bunny
|
|
1691
1695
|
end
|
1692
1696
|
|
1693
1697
|
# @private
|
1694
|
-
def handle_ack_or_nack(
|
1698
|
+
def handle_ack_or_nack(delivery_tag_before_offset, multiple, nack)
|
1699
|
+
delivery_tag = delivery_tag_before_offset + @delivery_tag_offset
|
1700
|
+
confirmed_range_start = multiple ? @delivery_tag_offset + 1 : delivery_tag
|
1701
|
+
confirmed_range_end = delivery_tag
|
1702
|
+
confirmed_range = (confirmed_range_start..confirmed_range_end)
|
1703
|
+
|
1695
1704
|
@unconfirmed_set_mutex.synchronize do
|
1696
1705
|
if nack
|
1697
|
-
|
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
|
1706
|
+
@nacked_set.merge(@unconfirmed_set & confirmed_range)
|
1704
1707
|
end
|
1705
1708
|
|
1706
|
-
|
1707
|
-
@unconfirmed_set.delete_if { |i| i <= delivery_tag }
|
1708
|
-
else
|
1709
|
-
@unconfirmed_set.delete(delivery_tag)
|
1710
|
-
end
|
1709
|
+
@unconfirmed_set.subtract(confirmed_range)
|
1711
1710
|
|
1712
1711
|
@only_acks_received = (@only_acks_received && !nack)
|
1713
1712
|
|
1714
1713
|
@confirms_continuations.push(true) if @unconfirmed_set.empty?
|
1715
|
-
|
1714
|
+
|
1715
|
+
if @confirms_callback
|
1716
|
+
confirmed_range.each { |tag| @confirms_callback.call(tag, false, nack) }
|
1717
|
+
end
|
1716
1718
|
end
|
1717
1719
|
end
|
1718
1720
|
|
@@ -1759,17 +1761,32 @@ module Bunny
|
|
1759
1761
|
@threads_waiting_on_confirms_continuations << t
|
1760
1762
|
|
1761
1763
|
begin
|
1762
|
-
|
1764
|
+
outstanding_confirms = false
|
1765
|
+
@unconfirmed_set_mutex.synchronize do
|
1766
|
+
outstanding_confirms = !@unconfirmed_set.empty?
|
1767
|
+
end
|
1768
|
+
@confirms_continuations.poll(@connection.continuation_timeout) if outstanding_confirms
|
1763
1769
|
ensure
|
1764
1770
|
@threads_waiting_on_confirms_continuations.delete(t)
|
1765
1771
|
end
|
1766
1772
|
else
|
1767
|
-
|
1773
|
+
unless @unconfirmed_set.empty?
|
1774
|
+
connection.reader_loop.run_once until @confirms_continuations.length > 0
|
1775
|
+
@confirms_continuations.pop
|
1776
|
+
end
|
1777
|
+
end
|
1778
|
+
end
|
1768
1779
|
|
1769
|
-
|
1780
|
+
# @private
|
1781
|
+
def read_and_reset_only_acks_received
|
1782
|
+
@unconfirmed_set_mutex.synchronize do
|
1783
|
+
result = @only_acks_received
|
1784
|
+
@only_acks_received = true
|
1785
|
+
result
|
1770
1786
|
end
|
1771
1787
|
end
|
1772
1788
|
|
1789
|
+
|
1773
1790
|
# Releases all continuations. Used by automatic network recovery.
|
1774
1791
|
# @private
|
1775
1792
|
def release_all_continuations
|
data/lib/bunny/version.rb
CHANGED
@@ -1,53 +1,13 @@
|
|
1
1
|
require "spec_helper"
|
2
2
|
|
3
3
|
describe Bunny::Channel do
|
4
|
-
let(:connection) do
|
5
|
-
c = Bunny.new(:user => "bunny_gem", :password => "bunny_password", :vhost => "bunny_testbed", :continuation_timeout => 10000)
|
6
|
-
c.start
|
7
|
-
c
|
8
|
-
end
|
9
|
-
|
10
4
|
after :each do
|
11
5
|
connection.close if connection.open?
|
12
6
|
end
|
13
7
|
|
14
8
|
let(:n) { 200 }
|
15
9
|
|
16
|
-
|
17
|
-
it "increments delivery index" do
|
18
|
-
ch = connection.create_channel
|
19
|
-
ch.should_not be_using_publisher_confirmations
|
20
|
-
|
21
|
-
ch.confirm_select
|
22
|
-
ch.should be_using_publisher_confirmations
|
23
|
-
|
24
|
-
q = ch.queue("", :exclusive => true)
|
25
|
-
x = ch.default_exchange
|
26
|
-
|
27
|
-
n.times do
|
28
|
-
x.publish("xyzzy", :routing_key => q.name)
|
29
|
-
end
|
30
|
-
|
31
|
-
ch.next_publish_seq_no.should == n + 1
|
32
|
-
ch.wait_for_confirms.should be_true
|
33
|
-
sleep 0.25
|
34
|
-
|
35
|
-
q.message_count.should == n
|
36
|
-
q.purge
|
37
|
-
|
38
|
-
ch.close
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
|
43
|
-
context "with a single-threaded connection" do
|
44
|
-
let(:connection) do
|
45
|
-
c = Bunny.new(:user => "bunny_gem", :password => "bunny_password", :vhost => "bunny_testbed", :continuation_timeout => 10000, :threaded => false)
|
46
|
-
c.start
|
47
|
-
c
|
48
|
-
end
|
49
|
-
|
50
|
-
|
10
|
+
shared_examples "publish confirms" do
|
51
11
|
context "when publishing with confirms enabled" do
|
52
12
|
it "increments delivery index" do
|
53
13
|
ch = connection.create_channel
|
@@ -72,6 +32,95 @@ describe Bunny::Channel do
|
|
72
32
|
|
73
33
|
ch.close
|
74
34
|
end
|
35
|
+
|
36
|
+
describe "#wait_for_confirms" do
|
37
|
+
it "should not hang when all the publishes are confirmed" do
|
38
|
+
ch = connection.create_channel
|
39
|
+
ch.should_not be_using_publisher_confirmations
|
40
|
+
|
41
|
+
ch.confirm_select
|
42
|
+
ch.should be_using_publisher_confirmations
|
43
|
+
|
44
|
+
q = ch.queue("", :exclusive => true)
|
45
|
+
x = ch.default_exchange
|
46
|
+
|
47
|
+
n.times do
|
48
|
+
x.publish("xyzzy", :routing_key => q.name)
|
49
|
+
end
|
50
|
+
|
51
|
+
ch.next_publish_seq_no.should == n + 1
|
52
|
+
ch.wait_for_confirms.should be_true
|
53
|
+
|
54
|
+
sleep 0.25
|
55
|
+
|
56
|
+
expect {
|
57
|
+
Bunny::Timeout.timeout(2) do
|
58
|
+
ch.wait_for_confirms.should be_true
|
59
|
+
end
|
60
|
+
}.not_to raise_error
|
61
|
+
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
context "when some of the messages get nacked" do
|
66
|
+
it "puts the nacks in the nacked_set" do
|
67
|
+
ch = connection.create_channel
|
68
|
+
ch.should_not be_using_publisher_confirmations
|
69
|
+
|
70
|
+
ch.confirm_select
|
71
|
+
ch.should be_using_publisher_confirmations
|
72
|
+
|
73
|
+
q = ch.queue("", :exclusive => true)
|
74
|
+
x = ch.default_exchange
|
75
|
+
|
76
|
+
n.times do
|
77
|
+
x.publish("xyzzy", :routing_key => q.name)
|
78
|
+
end
|
79
|
+
|
80
|
+
#be sneaky to simulate a nack
|
81
|
+
nacked_tag = nil
|
82
|
+
ch.instance_variable_get(:@unconfirmed_set_mutex).synchronize do
|
83
|
+
expect(ch.unconfirmed_set).to_not be_empty
|
84
|
+
nacked_tag = ch.unconfirmed_set.reduce(ch.next_publish_seq_no - 1) { |lowest, i| i < lowest ? i : lowest }
|
85
|
+
ch.handle_ack_or_nack(nacked_tag, false, true)
|
86
|
+
end
|
87
|
+
|
88
|
+
ch.nacked_set.should_not be_empty
|
89
|
+
ch.nacked_set.should include(nacked_tag)
|
90
|
+
|
91
|
+
ch.next_publish_seq_no.should == n + 1
|
92
|
+
ch.wait_for_confirms.should be_false
|
93
|
+
|
94
|
+
ch.nacked_set.should_not be_empty
|
95
|
+
ch.nacked_set.should include(nacked_tag)
|
96
|
+
|
97
|
+
sleep 0.25
|
98
|
+
q.message_count.should == n
|
99
|
+
q.purge
|
100
|
+
|
101
|
+
ch.close
|
102
|
+
end
|
103
|
+
end
|
75
104
|
end
|
76
105
|
end
|
106
|
+
|
107
|
+
context "with a multi-threaded connection" do
|
108
|
+
let(:connection) do
|
109
|
+
c = Bunny.new(:user => "bunny_gem", :password => "bunny_password", :vhost => "bunny_testbed", :continuation_timeout => 10000)
|
110
|
+
c.start
|
111
|
+
c
|
112
|
+
end
|
113
|
+
|
114
|
+
include_examples "publish confirms"
|
115
|
+
end
|
116
|
+
|
117
|
+
context "with a single-threaded connection" do
|
118
|
+
let(:connection) do
|
119
|
+
c = Bunny.new(:user => "bunny_gem", :password => "bunny_password", :vhost => "bunny_testbed", :continuation_timeout => 10000, :threaded => false)
|
120
|
+
c.start
|
121
|
+
c
|
122
|
+
end
|
123
|
+
|
124
|
+
include_examples "publish confirms"
|
125
|
+
end
|
77
126
|
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
require "spec_helper"
|
3
|
+
|
4
|
+
unless ENV["CI"]
|
5
|
+
describe "Message framing implementation" do
|
6
|
+
let(:connection) do
|
7
|
+
c = Bunny.new(:user => "bunny_gem",
|
8
|
+
:password => "bunny_password",
|
9
|
+
:vhost => "bunny_testbed",
|
10
|
+
:port => ENV.fetch("RABBITMQ_PORT", 5672))
|
11
|
+
c.start
|
12
|
+
c
|
13
|
+
end
|
14
|
+
|
15
|
+
after :each do
|
16
|
+
connection.close if connection.open?
|
17
|
+
end
|
18
|
+
|
19
|
+
|
20
|
+
context "with payload 272179 bytes in size" do
|
21
|
+
it "successfully frames the message" do
|
22
|
+
ch = connection.create_channel
|
23
|
+
|
24
|
+
q = ch.queue("", :exclusive => true)
|
25
|
+
x = ch.default_exchange
|
26
|
+
|
27
|
+
as = ("a" * 272179)
|
28
|
+
x.publish(as, :routing_key => q.name, :persistent => true)
|
29
|
+
|
30
|
+
sleep(1)
|
31
|
+
q.message_count.should == 1
|
32
|
+
|
33
|
+
_, _, payload = q.pop
|
34
|
+
payload.bytesize.should == as.bytesize
|
35
|
+
|
36
|
+
ch.close
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
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.
|
4
|
+
version: 1.4.0
|
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-
|
15
|
+
date: 2014-07-29 00:00:00.000000000 Z
|
16
16
|
dependencies:
|
17
17
|
- !ruby/object:Gem::Dependency
|
18
18
|
name: amq-protocol
|
@@ -184,6 +184,7 @@ files:
|
|
184
184
|
- spec/issues/issue100_spec.rb
|
185
185
|
- spec/issues/issue141_spec.rb
|
186
186
|
- spec/issues/issue202_spec.rb
|
187
|
+
- spec/issues/issue224_spec.rb
|
187
188
|
- spec/issues/issue78_spec.rb
|
188
189
|
- spec/issues/issue83_spec.rb
|
189
190
|
- spec/issues/issue97_attachment.json
|
@@ -281,6 +282,7 @@ test_files:
|
|
281
282
|
- spec/issues/issue100_spec.rb
|
282
283
|
- spec/issues/issue141_spec.rb
|
283
284
|
- spec/issues/issue202_spec.rb
|
285
|
+
- spec/issues/issue224_spec.rb
|
284
286
|
- spec/issues/issue78_spec.rb
|
285
287
|
- spec/issues/issue83_spec.rb
|
286
288
|
- spec/issues/issue97_attachment.json
|