bunny 2.5.1 → 2.6.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/.rspec +1 -3
- data/ChangeLog.md +23 -3
- data/README.md +2 -2
- data/lib/bunny/channel.rb +3 -5
- data/lib/bunny/consumer_work_pool.rb +15 -2
- data/lib/bunny/session.rb +2 -2
- data/lib/bunny/version.rb +1 -1
- data/spec/higher_level_api/integration/basic_cancel_spec.rb +62 -0
- data/spec/higher_level_api/integration/consistent_hash_exchange_spec.rb +24 -15
- data/spec/higher_level_api/integration/publisher_confirms_spec.rb +53 -0
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 00d3ad97db0f16249b51ccf1471f6b9c19a6a57d
|
4
|
+
data.tar.gz: 7011427b335e9a4913c180310c1bd3eec7b8f34f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: bc7a6e64cbee2ca138a14df95e7d84248262d1593dbd27832d9b03dbaef6b4d78df06bc5ce1777f313e3dae8f169672b1e8de8f93191e0b39b8e0e087a4898d9
|
7
|
+
data.tar.gz: fe51e2257d33a5954921cc55bb511ea8496ef2425030077894a098d4eb07efe899f58242be2f2db02e1da007d5d83add2dee03030d0bafd598c8ef61cb140255
|
data/.rspec
CHANGED
data/ChangeLog.md
CHANGED
@@ -1,9 +1,25 @@
|
|
1
|
-
## Changes between Bunny 2.5.
|
1
|
+
## Changes between Bunny 2.5.0 and 2.6.0 (unreleased)
|
2
2
|
|
3
|
-
|
3
|
+
### Graceful Shutdown of Consumers
|
4
4
|
|
5
|
+
Consumer work pool will now allow for a grace period before stopping
|
6
|
+
pool threads so that delivery processing in progress can have a chance to finish.
|
5
7
|
|
6
|
-
|
8
|
+
GitHub issue: [#437](https://github.com/ruby-amqp/bunny/pull/437)
|
9
|
+
|
10
|
+
Contributed by Stefan Sedich.
|
11
|
+
|
12
|
+
### `Bunny::Channel#wait_for_confirms` Now Throws When Used on a Closed Channel
|
13
|
+
|
14
|
+
GitHub issue: [#428](https://github.com/ruby-amqp/bunny/pull/428)
|
15
|
+
|
16
|
+
Contributed by Dimitar Dimitrov.
|
17
|
+
|
18
|
+
### Race Condition Eliminated in `Bunny::Channel#wait_for_confirms`
|
19
|
+
|
20
|
+
GitHub issue: [#424](https://github.com/ruby-amqp/bunny/issues/424)
|
21
|
+
|
22
|
+
Contributed by Dimitar Dimitrov.
|
7
23
|
|
8
24
|
### More Defensive Consumer Work Pool
|
9
25
|
|
@@ -49,6 +65,8 @@ Contributed by Dimitar Dimitrov.
|
|
49
65
|
|
50
66
|
## Changes between Bunny 2.3.0 and 2.4.0 (June 11th, 2016)
|
51
67
|
|
68
|
+
**This release includes minor breaking API changes**.
|
69
|
+
|
52
70
|
### Unconfirmed Delivery Tag Set Reset on Network Recovery
|
53
71
|
|
54
72
|
Channels will now reset their unconfirmed delivery tag set after
|
@@ -81,6 +99,8 @@ override a single key.
|
|
81
99
|
|
82
100
|
### More Predictable RABBITMQ_URL Handling
|
83
101
|
|
102
|
+
**This is a breaking API change**.
|
103
|
+
|
84
104
|
`RABBITMQ_URL` no longer will be used if any other
|
85
105
|
connection options are provided. This makes it possible
|
86
106
|
to use `RABBITMQ_URL` for some connections and options
|
data/README.md
CHANGED
@@ -59,7 +59,7 @@ Bunny `1.7.x` was the last version to support CRuby 1.9.3 and 1.8.7
|
|
59
59
|
|
60
60
|
## Supported RabbitMQ Versions
|
61
61
|
|
62
|
-
Bunny `1.5.0`
|
62
|
+
Bunny `1.5.0` and later versions only support RabbitMQ `3.3+`.
|
63
63
|
Bunny `1.4.x` and earlier supports RabbitMQ 2.x and 3.x.
|
64
64
|
|
65
65
|
|
@@ -88,7 +88,7 @@ gem install bunny
|
|
88
88
|
To use Bunny in a project managed with Bundler:
|
89
89
|
|
90
90
|
``` ruby
|
91
|
-
gem "bunny", ">= 2.
|
91
|
+
gem "bunny", ">= 2.5.1"
|
92
92
|
```
|
93
93
|
|
94
94
|
|
data/lib/bunny/channel.rb
CHANGED
@@ -952,7 +952,7 @@ module Bunny
|
|
952
952
|
@last_basic_cancel_ok = wait_on_continuations
|
953
953
|
end
|
954
954
|
|
955
|
-
|
955
|
+
@work_pool.shutdown(true) unless any_consumers?
|
956
956
|
|
957
957
|
@last_basic_cancel_ok
|
958
958
|
end
|
@@ -1790,11 +1790,9 @@ module Bunny
|
|
1790
1790
|
@threads_waiting_on_confirms_continuations << t
|
1791
1791
|
|
1792
1792
|
begin
|
1793
|
-
|
1794
|
-
|
1795
|
-
outstanding_confirms = !@unconfirmed_set.empty?
|
1793
|
+
while @unconfirmed_set_mutex.synchronize { !@unconfirmed_set.empty? }
|
1794
|
+
@confirms_continuations.poll(@connection.continuation_timeout)
|
1796
1795
|
end
|
1797
|
-
@confirms_continuations.poll(@connection.continuation_timeout) if outstanding_confirms
|
1798
1796
|
ensure
|
1799
1797
|
@threads_waiting_on_confirms_continuations.delete(t)
|
1800
1798
|
end
|
@@ -17,9 +17,12 @@ module Bunny
|
|
17
17
|
attr_reader :size
|
18
18
|
attr_reader :abort_on_exception
|
19
19
|
|
20
|
-
def initialize(size = 1, abort_on_exception = false)
|
20
|
+
def initialize(size = 1, abort_on_exception = false, shutdown_timeout = 60)
|
21
21
|
@size = size
|
22
22
|
@abort_on_exception = abort_on_exception
|
23
|
+
@shutdown_timeout = shutdown_timeout
|
24
|
+
@shutdown_mutex = ::Mutex.new
|
25
|
+
@shutdown_conditional = ::ConditionVariable.new
|
23
26
|
@queue = ::Queue.new
|
24
27
|
@paused = false
|
25
28
|
end
|
@@ -53,7 +56,7 @@ module Bunny
|
|
53
56
|
!@queue.empty?
|
54
57
|
end
|
55
58
|
|
56
|
-
def shutdown
|
59
|
+
def shutdown(wait_for_workers = false)
|
57
60
|
@running = false
|
58
61
|
|
59
62
|
@size.times do
|
@@ -61,6 +64,12 @@ module Bunny
|
|
61
64
|
throw :terminate
|
62
65
|
end
|
63
66
|
end
|
67
|
+
|
68
|
+
return unless wait_for_workers && @shutdown_timeout
|
69
|
+
|
70
|
+
@shutdown_mutex.synchronize do
|
71
|
+
@shutdown_conditional.wait(@shutdown_mutex, @shutdown_timeout)
|
72
|
+
end
|
64
73
|
end
|
65
74
|
|
66
75
|
def join(timeout = nil)
|
@@ -102,6 +111,10 @@ module Bunny
|
|
102
111
|
end
|
103
112
|
end
|
104
113
|
end
|
114
|
+
|
115
|
+
@shutdown_mutex.synchronize do
|
116
|
+
@shutdown_conditional.signal unless busy?
|
117
|
+
end
|
105
118
|
end
|
106
119
|
end
|
107
120
|
end
|
data/lib/bunny/session.rb
CHANGED
@@ -337,14 +337,14 @@ module Bunny
|
|
337
337
|
# opened (this operation is very fast and inexpensive).
|
338
338
|
#
|
339
339
|
# @return [Bunny::Channel] Newly opened channel
|
340
|
-
def create_channel(n = nil, consumer_pool_size = 1, consumer_pool_abort_on_exception = false)
|
340
|
+
def create_channel(n = nil, consumer_pool_size = 1, consumer_pool_abort_on_exception = false, consumer_pool_shutdown_timeout = 60)
|
341
341
|
raise ArgumentError, "channel number 0 is reserved in the protocol and cannot be used" if 0 == n
|
342
342
|
|
343
343
|
@channel_mutex.synchronize do
|
344
344
|
if n && (ch = @channels[n])
|
345
345
|
ch
|
346
346
|
else
|
347
|
-
ch = Bunny::Channel.new(self, n, ConsumerWorkPool.new(consumer_pool_size || 1, consumer_pool_abort_on_exception))
|
347
|
+
ch = Bunny::Channel.new(self, n, ConsumerWorkPool.new(consumer_pool_size || 1, consumer_pool_abort_on_exception, consumer_pool_shutdown_timeout))
|
348
348
|
ch.open
|
349
349
|
ch
|
350
350
|
end
|
data/lib/bunny/version.rb
CHANGED
@@ -73,4 +73,66 @@ describe Bunny::Consumer, "#cancel" do
|
|
73
73
|
expect(delivered_data).to be_empty
|
74
74
|
end
|
75
75
|
end
|
76
|
+
|
77
|
+
context "with a worker pool shutdown timeout configured" do
|
78
|
+
let(:queue_name) { "bunny.queues.#{rand}" }
|
79
|
+
|
80
|
+
it "processes the message if processing completes within the timeout" do
|
81
|
+
delivered_data = []
|
82
|
+
consumer = nil
|
83
|
+
|
84
|
+
t = Thread.new do
|
85
|
+
ch = connection.create_channel(nil, 1, false, 5)
|
86
|
+
q = ch.queue(queue_name, :auto_delete => true, :durable => false)
|
87
|
+
|
88
|
+
consumer = Bunny::Consumer.new(ch, q)
|
89
|
+
consumer.on_delivery do |_, _, payload|
|
90
|
+
sleep 2
|
91
|
+
delivered_data << payload
|
92
|
+
end
|
93
|
+
|
94
|
+
q.subscribe_with(consumer, :block => false)
|
95
|
+
end
|
96
|
+
t.abort_on_exception = true
|
97
|
+
sleep 1.0
|
98
|
+
|
99
|
+
ch = connection.create_channel
|
100
|
+
ch.default_exchange.publish("", :routing_key => queue_name)
|
101
|
+
sleep 0.7
|
102
|
+
|
103
|
+
consumer.cancel
|
104
|
+
sleep 1.0
|
105
|
+
|
106
|
+
expect(delivered_data).to_not be_empty
|
107
|
+
end
|
108
|
+
|
109
|
+
it "kills the consumer if processing takes longer than the timeout" do
|
110
|
+
delivered_data = []
|
111
|
+
consumer = nil
|
112
|
+
|
113
|
+
t = Thread.new do
|
114
|
+
ch = connection.create_channel(nil, 1, false, 1)
|
115
|
+
q = ch.queue(queue_name, :auto_delete => true, :durable => false)
|
116
|
+
|
117
|
+
consumer = Bunny::Consumer.new(ch, q)
|
118
|
+
consumer.on_delivery do |_, _, payload|
|
119
|
+
sleep 3
|
120
|
+
delivered_data << payload
|
121
|
+
end
|
122
|
+
|
123
|
+
q.subscribe_with(consumer, :block => false)
|
124
|
+
end
|
125
|
+
t.abort_on_exception = true
|
126
|
+
sleep 1.0
|
127
|
+
|
128
|
+
ch = connection.create_channel
|
129
|
+
ch.default_exchange.publish("", :routing_key => queue_name)
|
130
|
+
sleep 0.7
|
131
|
+
|
132
|
+
consumer.cancel
|
133
|
+
sleep 1.0
|
134
|
+
|
135
|
+
expect(delivered_data).to be_empty
|
136
|
+
end
|
137
|
+
end
|
76
138
|
end
|
@@ -1,23 +1,30 @@
|
|
1
1
|
# -*- coding: utf-8 -*-
|
2
2
|
require "spec_helper"
|
3
3
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
4
|
+
describe "x-consistent-hash exchange" do
|
5
|
+
let(:connection) do
|
6
|
+
c = Bunny.new(:user => "bunny_gem", :password => "bunny_password", :vhost => "bunny_testbed",
|
7
|
+
:automatically_recover => true)
|
8
|
+
c.start
|
9
|
+
c
|
10
|
+
end
|
11
|
+
|
12
|
+
let(:http_client) { RabbitMQ::HTTP::Client.new("http://127.0.0.1:15672") }
|
13
|
+
|
14
|
+
after :each do
|
15
|
+
connection.close
|
16
|
+
end
|
11
17
|
|
12
|
-
|
13
|
-
connection.close
|
14
|
-
end
|
18
|
+
let(:list) { Range.new(0, 6).to_a.map(&:to_s) }
|
15
19
|
|
16
|
-
|
20
|
+
let(:m) { 1500 }
|
17
21
|
|
18
|
-
|
22
|
+
let(:exchange_plugin_available) do
|
23
|
+
http_client.overview.exchange_types.map(&:name).include?("x-consistent-hash")
|
24
|
+
end
|
19
25
|
|
20
|
-
|
26
|
+
it "distributes messages between queues bound with the same routing key" do
|
27
|
+
if exchange_plugin_available
|
21
28
|
ch = connection.create_channel
|
22
29
|
body = "сообщение"
|
23
30
|
# requires the consistent hash exchange plugin,
|
@@ -45,6 +52,8 @@ unless ENV["CI"]
|
|
45
52
|
expect(q2.message_count).to be > 100
|
46
53
|
|
47
54
|
ch.close
|
48
|
-
|
49
|
-
|
55
|
+
else
|
56
|
+
skip "x-consistent-hash exchange type isn't available"
|
57
|
+
end # if
|
58
|
+
end # it
|
50
59
|
end
|
@@ -124,6 +124,59 @@ describe Bunny::Channel do
|
|
124
124
|
end
|
125
125
|
|
126
126
|
include_examples "publish confirms"
|
127
|
+
|
128
|
+
it "returns only when all confirmations for publishes are received" do
|
129
|
+
ch = connection.create_channel
|
130
|
+
|
131
|
+
operations_log = []
|
132
|
+
operations_log_mutex = Mutex.new
|
133
|
+
acks_received = Queue.new
|
134
|
+
|
135
|
+
log_acks = proc do |tag, _, is_nack|
|
136
|
+
operations_log_mutex.synchronize do
|
137
|
+
operation = "#{'n' if is_nack}ack_#{tag}"
|
138
|
+
operations_log << operation unless operations_log.include?(operation)
|
139
|
+
end
|
140
|
+
acks_received << true
|
141
|
+
end
|
142
|
+
|
143
|
+
ch.confirm_select(log_acks)
|
144
|
+
|
145
|
+
x = ch.default_exchange
|
146
|
+
q = ch.temporary_queue
|
147
|
+
|
148
|
+
x.publish('msg', routing_key: q.name)
|
149
|
+
|
150
|
+
# wait for the confirmation to arrive
|
151
|
+
acks_received.pop
|
152
|
+
|
153
|
+
# artificially simulate a slower ack. the test should work properly even
|
154
|
+
# without this patch, but it's here just to be sure we catch it.
|
155
|
+
def (x.channel).handle_ack_or_nack(delivery_tag_before_offset, multiple, nack)
|
156
|
+
sleep 0.1
|
157
|
+
super
|
158
|
+
end
|
159
|
+
|
160
|
+
x.publish('msg', routing_key: q.name)
|
161
|
+
x.publish('msg', routing_key: q.name)
|
162
|
+
|
163
|
+
if x.wait_for_confirms
|
164
|
+
operations_log_mutex.synchronize do
|
165
|
+
operations_log << 'all_confirmed'
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
# wait for all the confirmations to arrive
|
170
|
+
acks_received.pop
|
171
|
+
acks_received.pop
|
172
|
+
|
173
|
+
expect(operations_log).to eq([
|
174
|
+
'ack_1',
|
175
|
+
'ack_2',
|
176
|
+
'ack_3',
|
177
|
+
'all_confirmed',
|
178
|
+
])
|
179
|
+
end
|
127
180
|
end
|
128
181
|
|
129
182
|
context "with a single-threaded connection" do
|
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: 2.
|
4
|
+
version: 2.6.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: 2016-
|
15
|
+
date: 2016-10-14 00:00:00.000000000 Z
|
16
16
|
dependencies:
|
17
17
|
- !ruby/object:Gem::Dependency
|
18
18
|
name: amq-protocol
|