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