bunny 1.3.1 → 1.4.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 +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
|