beetle 3.0.0.rc5 → 3.0.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/RELEASE_NOTES.rdoc +16 -22
- data/Rakefile +1 -1
- data/examples/throttling.rb +68 -0
- data/lib/beetle.rb +1 -1
- data/lib/beetle/base.rb +1 -0
- data/lib/beetle/client.rb +27 -4
- data/lib/beetle/configuration.rb +8 -4
- data/lib/beetle/publisher.rb +51 -0
- data/lib/beetle/{dead_lettering.rb → queue_properties.rb} +61 -5
- data/lib/beetle/subscriber.rb +11 -2
- data/lib/beetle/version.rb +1 -1
- data/test/beetle/base_test.rb +2 -0
- data/test/beetle/client_test.rb +15 -3
- data/test/beetle/publisher_test.rb +53 -0
- data/test/beetle/queue_properties_test.rb +210 -0
- data/test/beetle/subscriber_test.rb +1 -1
- metadata +6 -5
- data/test/beetle/dead_lettering_test.rb +0 -117
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8a90e706d339d2a9e458c0b82113b58d5be98243fa9c9adbeaafb12fadeeb3d1
|
4
|
+
data.tar.gz: d89db5e989cfa51558ebda9db9c6acd10170c27fda0135378157e252570be626
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ee25e895ba9f3f38afe6d4985297435d93cab432b0dd8d483b8890a25b58f89d9993fac429c0d710bfeed49568dd1a28c948a0241297c1352ad2200987e0aebc
|
7
|
+
data.tar.gz: d1dff384a6bd1da983b2c400e524970d086759ae7c24106089ef0e36a167b7cb9b8769f6938b96b9a5b78435abb945cddba432b14755716f67c96e508783ef51
|
data/RELEASE_NOTES.rdoc
CHANGED
@@ -1,36 +1,30 @@
|
|
1
1
|
= Release Notes
|
2
2
|
|
3
|
-
== Version 3.0.0
|
4
|
-
* ake sure to clean dedup store when ack_count is larger than 2
|
3
|
+
== Version 3.0.0
|
5
4
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
*
|
12
|
-
|
13
|
-
|
14
|
-
== Version 3.0.0.rc2
|
5
|
+
* provide client method to setup queues and queue policies.
|
6
|
+
Setting up queue policies on demand in publisher and subscriber is OK
|
7
|
+
for a small number of queues, publishers and subscribers. But the HTTP
|
8
|
+
API of RabbitMQ doesn't scale all that well, so that a large number
|
9
|
+
of HTTP calls to set up queue policies can in fact crash a server.
|
10
|
+
* allow queue mode specification and dead lettering specification on a
|
11
|
+
per queue basis.
|
15
12
|
* change policy setup to be asynchronous, on demand in publisher and
|
16
13
|
consumer. Users have to run a processors to listen to messages and
|
17
14
|
call setup_queue_policies! with the parses JSON paylod of the
|
18
15
|
message.
|
19
|
-
*
|
20
|
-
|
21
|
-
* added delete_queue_keys command to beetle to allow deletion of
|
22
|
-
excess dedup store entries for a given queue.
|
16
|
+
* store redis gc stats in redis and display them in the configuration
|
17
|
+
server web UI
|
23
18
|
* config server: store current master server in consul, if consul
|
24
19
|
config has been provided.
|
25
20
|
* config server: server correctly updates configured client ids when
|
26
21
|
they change in consul.
|
27
|
-
|
28
|
-
|
29
|
-
*
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
of HTTP calls to set up queue policies can in fact crash a server.
|
22
|
+
* don't create dead letter queues when using the trace functionality
|
23
|
+
* make sure to clean dedup store when ack_count is larger than 2
|
24
|
+
* added dump_expiries command to beetle to dump dediplication store
|
25
|
+
expiry times.
|
26
|
+
* added delete_queue_keys command to beetle to allow deletion of
|
27
|
+
excess dedup store entries for a given queue.
|
34
28
|
|
35
29
|
== Version 2.3.2
|
36
30
|
* config server: fixed a race condition when accessing server state.
|
data/Rakefile
CHANGED
@@ -0,0 +1,68 @@
|
|
1
|
+
# throttling.rb
|
2
|
+
# this example shows you how throttling the publisher works
|
3
|
+
#
|
4
|
+
# ! check the examples/README.rdoc for information on starting your redis/rabbit !
|
5
|
+
#
|
6
|
+
# start it with ruby throttling.rb
|
7
|
+
|
8
|
+
require "rubygems"
|
9
|
+
require File.expand_path("../lib/beetle", File.dirname(__FILE__))
|
10
|
+
|
11
|
+
# set Beetle log level to info, less noisy than debug
|
12
|
+
Beetle.config.logger.level = Logger::INFO
|
13
|
+
# override default of 60 seconds
|
14
|
+
Beetle.config.throttling_refresh_interval = 5
|
15
|
+
|
16
|
+
# setup clients
|
17
|
+
client = Beetle::Client.new
|
18
|
+
client.register_queue(:test)
|
19
|
+
client.register_message(:test)
|
20
|
+
client.throttle(:test => 50)
|
21
|
+
|
22
|
+
consumer = Beetle::Client.new
|
23
|
+
consumer.register_queue(:test)
|
24
|
+
consumer.register_message(:test)
|
25
|
+
|
26
|
+
# purge the test queue
|
27
|
+
client.purge(:test)
|
28
|
+
|
29
|
+
# empty the dedup store
|
30
|
+
client.deduplication_store.flushdb
|
31
|
+
|
32
|
+
# register our handler to the message, check out the message.rb for more stuff you can get from the message object
|
33
|
+
messages_received = 0
|
34
|
+
consumer.register_handler(:test) do |message|
|
35
|
+
sleep 0.2
|
36
|
+
messages_received += 1
|
37
|
+
puts "Received #{messages_received} messages"
|
38
|
+
end
|
39
|
+
|
40
|
+
interrupted = false
|
41
|
+
|
42
|
+
t = Thread.new do
|
43
|
+
c = 0
|
44
|
+
loop do
|
45
|
+
break if c == 200 || interrupted
|
46
|
+
100.times do |i|
|
47
|
+
client.publish(:test, (c+=1).to_s)
|
48
|
+
puts "Published message #{c}"
|
49
|
+
sleep 0.1
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
trap('INT') do
|
55
|
+
interrupted = true
|
56
|
+
consumer.stop_listening
|
57
|
+
end
|
58
|
+
|
59
|
+
# start listening
|
60
|
+
# this starts the event machine event loop using EM.run
|
61
|
+
# the block passed to listen will be yielded as the last step of the setup process
|
62
|
+
consumer.listen do
|
63
|
+
EM.add_periodic_timer(1) do
|
64
|
+
consumer.stop_listening if messages_received >= 200
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
t.join
|
data/lib/beetle.rb
CHANGED
@@ -50,7 +50,7 @@ module Beetle
|
|
50
50
|
# use ruby's autoload mechanism for loading beetle classes
|
51
51
|
lib_dir = File.expand_path(File.dirname(__FILE__) + '/beetle/')
|
52
52
|
Dir["#{lib_dir}/*.rb"].each do |libfile|
|
53
|
-
autoload File.basename(libfile)[/^(.*)\.rb$/, 1].
|
53
|
+
autoload File.basename(libfile)[/^(.*)\.rb$/, 1].camelize, libfile
|
54
54
|
end
|
55
55
|
|
56
56
|
require "#{lib_dir}/redis_ext"
|
data/lib/beetle/base.rb
CHANGED
data/lib/beetle/client.rb
CHANGED
@@ -55,7 +55,7 @@ module Beetle
|
|
55
55
|
@messages = {}
|
56
56
|
@bindings = {}
|
57
57
|
@deduplication_store = DeduplicationStore.new(config)
|
58
|
-
@
|
58
|
+
@queue_properties = QueueProperties.new(config)
|
59
59
|
load_brokers_from_config
|
60
60
|
register_exchange(config.beetle_policy_exchange_name)
|
61
61
|
# make sure dead lettering is false for the policy update queue
|
@@ -258,6 +258,27 @@ module Beetle
|
|
258
258
|
subscriber.resume_listening(queues)
|
259
259
|
end
|
260
260
|
|
261
|
+
# throttle publishing of messages based on queue lengths.
|
262
|
+
#
|
263
|
+
# client.throttle(:foo => 10000, :bar => 10_000)
|
264
|
+
#
|
265
|
+
# throttle publisher to 1 message per second as long as queue foo has more
|
266
|
+
# than 10000 entries or queue bar has more than 100000 entries across all
|
267
|
+
# servers. Queue lenghts are periodically determined during publishing. You
|
268
|
+
# only want to use this feature if you plan to publish a huge amount of
|
269
|
+
# messages to slow consumers so as to not overload the broker or the redis
|
270
|
+
# deduplication store. You'll want to use this feature when running background
|
271
|
+
# jobs that publish huge amounts of messages to avoid overloading brokers
|
272
|
+
# and the message deduplication store.
|
273
|
+
def throttle(throttling_options)
|
274
|
+
publisher.throttle(throttling_options.stringify_keys)
|
275
|
+
end
|
276
|
+
|
277
|
+
# is the publisher currently throttled?
|
278
|
+
def throttled?
|
279
|
+
publisher.throttled?
|
280
|
+
end
|
281
|
+
|
261
282
|
# traces queues without consuming them. useful for debugging message flow.
|
262
283
|
def trace(queue_names=self.queues.keys, tracer=nil, &block)
|
263
284
|
queues_to_trace = self.queues.slice(*queue_names)
|
@@ -275,7 +296,9 @@ module Beetle
|
|
275
296
|
puts "DATA: #{msg.data}"
|
276
297
|
end
|
277
298
|
register_handler(queue_names){|msg| tracer.call msg }
|
299
|
+
@subscriber.tracing = true
|
278
300
|
listen_queues(queue_names, &block)
|
301
|
+
@subscriber.tracing = false
|
279
302
|
end
|
280
303
|
|
281
304
|
# evaluate the ruby files matching the given +glob+ pattern in the context of the client instance.
|
@@ -299,8 +322,8 @@ module Beetle
|
|
299
322
|
@subscriber = nil
|
300
323
|
end
|
301
324
|
|
302
|
-
def
|
303
|
-
@
|
325
|
+
def update_queue_properties!(message_payload)
|
326
|
+
@queue_properties.update_queue_properties!(message_payload)
|
304
327
|
end
|
305
328
|
|
306
329
|
private
|
@@ -350,7 +373,7 @@ module Beetle
|
|
350
373
|
end
|
351
374
|
|
352
375
|
def queue_name_for_tracing(queue)
|
353
|
-
"trace-#{queue}-#{Beetle.hostname}
|
376
|
+
"trace-#{queue}-#{Beetle.hostname}"
|
354
377
|
end
|
355
378
|
|
356
379
|
def load_brokers_from_config
|
data/lib/beetle/configuration.rb
CHANGED
@@ -93,7 +93,7 @@ module Beetle
|
|
93
93
|
attr_accessor :dead_lettering_msg_ttl
|
94
94
|
|
95
95
|
# Read timeout for http requests to create dead letter bindings
|
96
|
-
attr_accessor :
|
96
|
+
attr_accessor :rabbitmq_api_read_timeout
|
97
97
|
|
98
98
|
# Returns the port on which the Rabbit API is hosted
|
99
99
|
attr_accessor :api_port
|
@@ -112,6 +112,9 @@ module Beetle
|
|
112
112
|
# decreased parallelism.
|
113
113
|
attr_accessor :prefetch_count
|
114
114
|
|
115
|
+
# refresh interval for determining queue lenghts for throttling.
|
116
|
+
attr_accessor :throttling_refresh_interval
|
117
|
+
|
115
118
|
# directory to store large intermediate files (defaults '/tmp')
|
116
119
|
attr_accessor :tmpdir
|
117
120
|
|
@@ -156,13 +159,14 @@ module Beetle
|
|
156
159
|
self.prefetch_count = 1
|
157
160
|
|
158
161
|
self.dead_lettering_enabled = false
|
159
|
-
self.dead_lettering_msg_ttl = 1000
|
160
|
-
self.
|
162
|
+
self.dead_lettering_msg_ttl = 1000 # 1 second
|
163
|
+
self.rabbitmq_api_read_timeout = 5 # 5 seconds
|
161
164
|
|
162
165
|
self.lazy_queues_enabled = false
|
166
|
+
self.throttling_refresh_interval = 60 # seconds
|
163
167
|
|
164
168
|
self.publishing_timeout = 0
|
165
|
-
self.publisher_connect_timeout = 5
|
169
|
+
self.publisher_connect_timeout = 5 # seconds
|
166
170
|
self.tmpdir = "/tmp"
|
167
171
|
|
168
172
|
self.log_file = STDOUT
|
data/lib/beetle/publisher.rb
CHANGED
@@ -9,9 +9,24 @@ module Beetle
|
|
9
9
|
@exchanges_with_bound_queues = {}
|
10
10
|
@dead_servers = {}
|
11
11
|
@bunnies = {}
|
12
|
+
@throttling_options = {}
|
13
|
+
@next_throttle_refresh = Time.now
|
14
|
+
@throttled = false
|
12
15
|
at_exit { stop }
|
13
16
|
end
|
14
17
|
|
18
|
+
def throttled?
|
19
|
+
@throttled
|
20
|
+
end
|
21
|
+
|
22
|
+
def throttling?
|
23
|
+
!@throttling_options.empty?
|
24
|
+
end
|
25
|
+
|
26
|
+
def throttling_status
|
27
|
+
@throttled ? 'throttled' : 'unthrottled'
|
28
|
+
end
|
29
|
+
|
15
30
|
# list of exceptions potentially raised by bunny
|
16
31
|
# these need to be lazy, because qrack exceptions are only defined after a connection has been established
|
17
32
|
def bunny_exceptions
|
@@ -29,6 +44,7 @@ module Beetle
|
|
29
44
|
exchange_name = opts.delete(:exchange)
|
30
45
|
opts.delete(:queue)
|
31
46
|
recycle_dead_servers unless @dead_servers.empty?
|
47
|
+
throttle!
|
32
48
|
if opts[:redundant]
|
33
49
|
publish_with_redundancy(exchange_name, message_name, data, opts)
|
34
50
|
else
|
@@ -135,6 +151,16 @@ module Beetle
|
|
135
151
|
[status, result]
|
136
152
|
end
|
137
153
|
|
154
|
+
def throttle(queue_options)
|
155
|
+
@throttling_options = queue_options
|
156
|
+
end
|
157
|
+
|
158
|
+
def throttle!
|
159
|
+
return unless throttling?
|
160
|
+
refresh_throttling!
|
161
|
+
sleep 1 if throttled?
|
162
|
+
end
|
163
|
+
|
138
164
|
def purge(queue_names) #:nodoc:
|
139
165
|
each_server do
|
140
166
|
queue_names.each do |name|
|
@@ -251,5 +277,30 @@ module Beetle
|
|
251
277
|
@exchanges[@server] = {}
|
252
278
|
@queues[@server] = {}
|
253
279
|
end
|
280
|
+
|
281
|
+
def refresh_throttling!
|
282
|
+
t = Time.now
|
283
|
+
return if t < @next_throttle_refresh
|
284
|
+
@next_throttle_refresh = t + @client.config.throttling_refresh_interval
|
285
|
+
old_throttled = @throttled
|
286
|
+
@throttled = false
|
287
|
+
@throttling_options.each do |queue_name, max_length|
|
288
|
+
begin
|
289
|
+
len = 0
|
290
|
+
each_server do
|
291
|
+
len += queue(queue_name).status[:message_count]
|
292
|
+
end
|
293
|
+
# logger.debug "Beetle: queue '#{queue_name}' has size #{len}"
|
294
|
+
if len > max_length
|
295
|
+
@throttled = true
|
296
|
+
break
|
297
|
+
end
|
298
|
+
rescue => e
|
299
|
+
logger.warn "Beetle: could not fetch queue length for queue '#{queue_name}': #{e}"
|
300
|
+
end
|
301
|
+
end
|
302
|
+
logger.info "Beetle: publisher #{throttling_status}" if @throttled != old_throttled
|
303
|
+
end
|
304
|
+
|
254
305
|
end
|
255
306
|
end
|
@@ -2,7 +2,7 @@ require 'net/http'
|
|
2
2
|
require 'json'
|
3
3
|
|
4
4
|
module Beetle
|
5
|
-
class
|
5
|
+
class QueueProperties
|
6
6
|
class FailedRabbitRequest < StandardError; end
|
7
7
|
|
8
8
|
attr_reader :config
|
@@ -11,8 +11,12 @@ module Beetle
|
|
11
11
|
@config = config
|
12
12
|
end
|
13
13
|
|
14
|
-
def
|
15
|
-
|
14
|
+
def vhost
|
15
|
+
CGI.escape(@config.vhost)
|
16
|
+
end
|
17
|
+
|
18
|
+
def update_queue_properties!(options)
|
19
|
+
logger.info "Updating queue properties: #{options.inspect}"
|
16
20
|
options = options.symbolize_keys
|
17
21
|
server = options[:server]
|
18
22
|
target_queue = options[:queue_name]
|
@@ -21,6 +25,7 @@ module Beetle
|
|
21
25
|
|
22
26
|
target_queue_options = policy_options.merge(:routing_key => dead_letter_queue_name)
|
23
27
|
set_queue_policy!(server, target_queue, target_queue_options)
|
28
|
+
remove_obsolete_bindings(server, target_queue, options[:bindings]) if options.has_key?(:bindings)
|
24
29
|
|
25
30
|
dead_letter_queue_options = policy_options.merge(:routing_key => target_queue, :message_ttl => options[:message_ttl])
|
26
31
|
set_queue_policy!(server, dead_letter_queue_name, dead_letter_queue_options)
|
@@ -34,7 +39,6 @@ module Beetle
|
|
34
39
|
|
35
40
|
return unless options[:dead_lettering] || options[:lazy]
|
36
41
|
|
37
|
-
vhost = CGI.escape(config.vhost)
|
38
42
|
# no need to worry that the server has the port 5672. Net:HTTP will take care of this. See below.
|
39
43
|
request_url = URI("http://#{server}/api/policies/#{vhost}/#{queue_name}_policy")
|
40
44
|
request = Net::HTTP::Put.new(request_url)
|
@@ -68,11 +72,63 @@ module Beetle
|
|
68
72
|
:ok
|
69
73
|
end
|
70
74
|
|
75
|
+
def remove_obsolete_bindings(server, queue_name, bindings)
|
76
|
+
logger.debug "Removing obsolete bindings"
|
77
|
+
raise ArgumentError.new("server missing") if server.blank?
|
78
|
+
raise ArgumentError.new("queue name missing") if queue_name.blank?
|
79
|
+
raise ArgumentError.new("bindings missing") if bindings.nil?
|
80
|
+
|
81
|
+
desired_bindings = bindings.each_with_object({}) do |b, desired|
|
82
|
+
desired[[b[:exchange], b[:key]]] = b.except(:exchange, :key)
|
83
|
+
end
|
84
|
+
|
85
|
+
server_bindings = retrieve_bindings(server, queue_name)
|
86
|
+
server_bindings.each do |b|
|
87
|
+
next unless b["destination_type"] == "queue" || b["destination"] == queue_name
|
88
|
+
next if b["source"] == ""
|
89
|
+
source_route = b.values_at("source", "routing_key")
|
90
|
+
unless desired_bindings.has_key?(source_route)
|
91
|
+
logger.info "Removing obsolete binding: #{b.inspect}"
|
92
|
+
remove_binding(server, queue_name, b["source"], b["properties_key"])
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def retrieve_bindings(server, queue_name)
|
98
|
+
request_url = URI("http://#{server}/api/queues/#{vhost}/#{queue_name}/bindings")
|
99
|
+
request = Net::HTTP::Get.new(request_url)
|
100
|
+
|
101
|
+
response = run_rabbit_http_request(request_url, request) do |http|
|
102
|
+
http.request(request)
|
103
|
+
end
|
104
|
+
|
105
|
+
unless response.code == "200"
|
106
|
+
log_error("Failed to retrieve bindings for queue #{queue_name}", response)
|
107
|
+
raise FailedRabbitRequest.new("Could not retrieve queue bindings")
|
108
|
+
end
|
109
|
+
|
110
|
+
JSON.parse(response.body)
|
111
|
+
end
|
112
|
+
|
113
|
+
def remove_binding(server, queue_name, exchange, properties_key)
|
114
|
+
request_url = URI("http://#{server}/api/bindings/#{vhost}/e/#{exchange}/q/#{queue_name}/#{properties_key}")
|
115
|
+
request = Net::HTTP::Delete.new(request_url)
|
116
|
+
|
117
|
+
response = run_rabbit_http_request(request_url, request) do |http|
|
118
|
+
http.request(request)
|
119
|
+
end
|
120
|
+
|
121
|
+
unless %w(200 201 204).include?(response.code)
|
122
|
+
log_error("Failed to remove obsolete binding for queue #{queue_name}", response)
|
123
|
+
raise FailedRabbitRequest.new("Could not retrieve queue bindings")
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
71
127
|
def run_rabbit_http_request(uri, request, &block)
|
72
128
|
request.basic_auth(config.user, config.password)
|
73
129
|
request["Content-Type"] = "application/json"
|
74
130
|
http = Net::HTTP.new(uri.hostname, config.api_port)
|
75
|
-
http.read_timeout = config.
|
131
|
+
http.read_timeout = config.rabbitmq_api_read_timeout
|
76
132
|
# don't do this in production:
|
77
133
|
# http.set_debug_output(logger.instance_eval{ @logdev.dev })
|
78
134
|
http.start do |instance|
|
data/lib/beetle/subscriber.rb
CHANGED
@@ -4,6 +4,11 @@ module Beetle
|
|
4
4
|
# Manages subscriptions and message processing on the receiver side of things.
|
5
5
|
class Subscriber < Base
|
6
6
|
|
7
|
+
attr_accessor :tracing
|
8
|
+
def tracing?
|
9
|
+
@tracing
|
10
|
+
end
|
11
|
+
|
7
12
|
# create a new subscriber instance
|
8
13
|
def initialize(client, options = {}) #:nodoc:
|
9
14
|
super
|
@@ -14,6 +19,7 @@ module Beetle
|
|
14
19
|
@subscriptions = {}
|
15
20
|
@listened_queues = []
|
16
21
|
@channels_closed = false
|
22
|
+
@tracing = false
|
17
23
|
end
|
18
24
|
|
19
25
|
# the client calls this method to subscribe to a list of queues.
|
@@ -206,8 +212,11 @@ module Beetle
|
|
206
212
|
|
207
213
|
def bind_queue!(queue_name, creation_keys, exchange_name, binding_keys)
|
208
214
|
queue = channel.queue(queue_name, creation_keys)
|
209
|
-
|
210
|
-
|
215
|
+
unless tracing?
|
216
|
+
# we don't want to create dead-letter queues for tracing
|
217
|
+
policy_options = bind_dead_letter_queue!(channel, queue_name, creation_keys)
|
218
|
+
publish_policy_options(policy_options)
|
219
|
+
end
|
211
220
|
exchange = exchange(exchange_name)
|
212
221
|
queue.bind(exchange, binding_keys)
|
213
222
|
queue
|
data/lib/beetle/version.rb
CHANGED
data/test/beetle/base_test.rb
CHANGED
@@ -68,6 +68,7 @@ module Beetle
|
|
68
68
|
channel = stub('channel')
|
69
69
|
expected_options = {
|
70
70
|
:queue_name => "QUEUE_NAME",
|
71
|
+
:bindings=>[{:exchange=>"QUEUE_NAME", :key=>"QUEUE_NAME"}],
|
71
72
|
:dead_letter_queue_name=>"QUEUE_NAME_dead_letter",
|
72
73
|
:message_ttl => 1000,
|
73
74
|
:dead_lettering => false,
|
@@ -84,6 +85,7 @@ module Beetle
|
|
84
85
|
|
85
86
|
expected_options = {
|
86
87
|
:queue_name => "QUEUE_NAME",
|
88
|
+
:bindings=>[{:exchange=>"QUEUE_NAME", :key=>"QUEUE_NAME"}],
|
87
89
|
:dead_letter_queue_name=>"QUEUE_NAME_dead_letter",
|
88
90
|
:message_ttl => 1000,
|
89
91
|
:dead_lettering => true,
|
data/test/beetle/client_test.rb
CHANGED
@@ -356,10 +356,10 @@ module Beetle
|
|
356
356
|
client.stop_listening
|
357
357
|
end
|
358
358
|
|
359
|
-
test "should delegate
|
359
|
+
test "should delegate update_queue_properties! to the queue policies instance" do
|
360
360
|
client = Client.new
|
361
|
-
client.instance_variable_get(:@
|
362
|
-
client.
|
361
|
+
client.instance_variable_get(:@queue_properties).expects(:update_queue_properties!)
|
362
|
+
client.update_queue_properties!({})
|
363
363
|
end
|
364
364
|
|
365
365
|
test "should delegate pause_listening to the subscriber instance" do
|
@@ -430,6 +430,18 @@ module Beetle
|
|
430
430
|
client.trace(["test"])
|
431
431
|
end
|
432
432
|
|
433
|
+
test "delegates setting throttling options to the publisher instance and stringifies the queue names" do
|
434
|
+
client = Client.new
|
435
|
+
client.send(:publisher).expects(:throttle).with("test" => 1)
|
436
|
+
client.throttle(:test => 1)
|
437
|
+
end
|
438
|
+
|
439
|
+
test "delegates querying the throttling status to the publisher instance" do
|
440
|
+
client = Client.new
|
441
|
+
client.send(:publisher).expects(:throttled?)
|
442
|
+
client.throttled?
|
443
|
+
end
|
444
|
+
|
433
445
|
def message_stub_for_tracing
|
434
446
|
header_stub = stub_everything("header")
|
435
447
|
header_stub.stubs(:method).returns(stub_everything("method"))
|
@@ -80,6 +80,7 @@ module Beetle
|
|
80
80
|
@pub.send(:mark_server_dead)
|
81
81
|
publishing = sequence('publishing')
|
82
82
|
@pub.expects(:recycle_dead_servers).in_sequence(publishing)
|
83
|
+
@pub.expects(:throttle!).in_sequence(publishing)
|
83
84
|
@pub.expects(:publish_with_failover).with("mama-exchange", "mama", @data, @opts).in_sequence(publishing)
|
84
85
|
@pub.publish("mama", @data)
|
85
86
|
end
|
@@ -89,6 +90,7 @@ module Beetle
|
|
89
90
|
@pub.send(:mark_server_dead)
|
90
91
|
publishing = sequence('publishing')
|
91
92
|
@pub.expects(:recycle_dead_servers).in_sequence(publishing)
|
93
|
+
@pub.expects(:throttle!).in_sequence(publishing)
|
92
94
|
@pub.expects(:publish_with_redundancy).with("mama-exchange", "mama", @data, @opts.merge(:redundant => true)).in_sequence(publishing)
|
93
95
|
@pub.publish("mama", @data, :redundant => true)
|
94
96
|
end
|
@@ -339,6 +341,57 @@ module Beetle
|
|
339
341
|
@pub.setup_queues_and_policies(["queue"])
|
340
342
|
end
|
341
343
|
|
344
|
+
test "reports whether it has been throttled" do
|
345
|
+
assert !@pub.throttled?
|
346
|
+
@pub.instance_variable_set :@throttled, true
|
347
|
+
assert @pub.throttled?
|
348
|
+
end
|
349
|
+
|
350
|
+
test "sets throttling options" do
|
351
|
+
h = { "x" => 1, "y" => 2}
|
352
|
+
@pub.throttle(h)
|
353
|
+
assert_equal h, @pub.instance_variable_get(:@throttling_options)
|
354
|
+
end
|
355
|
+
|
356
|
+
test "throttle! sleeps appropriately when refreshing throttling" do
|
357
|
+
@pub.expects(:throttling?).returns(true).twice
|
358
|
+
@pub.expects(:refresh_throttling!).twice
|
359
|
+
@pub.expects(:throttled?).returns(true)
|
360
|
+
@pub.expects(:sleep).with(1)
|
361
|
+
@pub.throttle!
|
362
|
+
@pub.expects(:throttled?).returns(false)
|
363
|
+
@pub.expects(:sleep).never
|
364
|
+
@pub.throttle!
|
365
|
+
end
|
366
|
+
|
367
|
+
test "returns a throttling status" do
|
368
|
+
assert_equal 'unthrottled', @pub.throttling_status
|
369
|
+
@pub.instance_variable_set :@throttled, true
|
370
|
+
assert_equal 'throttled', @pub.throttling_status
|
371
|
+
end
|
372
|
+
|
373
|
+
test "refresh_throttling! does not recompute values when refresh interval has not passed" do
|
374
|
+
@pub.instance_variable_set :@next_throttle_refresh, Time.now + 1
|
375
|
+
options = {}
|
376
|
+
@pub.throttle(options)
|
377
|
+
options.expects(:each).never
|
378
|
+
@pub.__send__ :refresh_throttling!
|
379
|
+
end
|
380
|
+
|
381
|
+
test "refresh_throttling! throttles when queue length exceeds limit" do
|
382
|
+
assert !@pub.throttled?
|
383
|
+
@pub.instance_variable_set :@next_throttle_refresh, Time.now - 1
|
384
|
+
options = { "test" => 100 }
|
385
|
+
@pub.throttle(options)
|
386
|
+
@pub.expects(:each_server).yields
|
387
|
+
q = mock("queue")
|
388
|
+
q.expects(:status).returns(:message_count => 500)
|
389
|
+
@pub.expects(:queue).returns(q)
|
390
|
+
@pub.logger.expects(:info)
|
391
|
+
@pub.__send__ :refresh_throttling!
|
392
|
+
assert @pub.throttled?
|
393
|
+
end
|
394
|
+
|
342
395
|
end
|
343
396
|
|
344
397
|
class PublisherExchangeManagementTest < Minitest::Test
|
@@ -0,0 +1,210 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
|
2
|
+
|
3
|
+
module Beetle
|
4
|
+
class SetDeadLetterPolicyTest < Minitest::Test
|
5
|
+
def setup
|
6
|
+
@server = "localhost:15672"
|
7
|
+
@queue_name = "QUEUE_NAME"
|
8
|
+
@config = Configuration.new
|
9
|
+
@config.logger = Logger.new("/dev/null")
|
10
|
+
@queue_properties = QueueProperties.new(@config)
|
11
|
+
end
|
12
|
+
|
13
|
+
test "raises exception when queue name wasn't specified" do
|
14
|
+
assert_raises ArgumentError do
|
15
|
+
@queue_properties.set_queue_policy!(@server, "")
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
test "raises exception when no server was specified" do
|
20
|
+
assert_raises ArgumentError do
|
21
|
+
@queue_properties.set_queue_policy!("", @queue_name)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
test "update_queue_properties! calls set_queue_policy for both target queue and dead letter queue" do
|
26
|
+
options = {
|
27
|
+
:server => "server", :lazy => true, :dead_lettering => true,
|
28
|
+
:queue_name => "QUEUE_NAME", :dead_letter_queue_name => "QUEUE_NAME_dead_letter",
|
29
|
+
:message_ttl => 10000
|
30
|
+
}
|
31
|
+
@queue_properties.expects(:set_queue_policy!).with("server", "QUEUE_NAME",
|
32
|
+
:lazy => true, :dead_lettering => true,
|
33
|
+
:routing_key => "QUEUE_NAME_dead_letter")
|
34
|
+
@queue_properties.expects(:set_queue_policy!).with("server", "QUEUE_NAME_dead_letter",
|
35
|
+
:lazy => true, :dead_lettering => true,
|
36
|
+
:routing_key => "QUEUE_NAME",
|
37
|
+
:message_ttl => 10000)
|
38
|
+
@queue_properties.update_queue_properties!(options)
|
39
|
+
end
|
40
|
+
|
41
|
+
test "creates a policy by posting to the rabbitmq if dead lettering is enabled" do
|
42
|
+
stub_request(:put, "http://localhost:15672/api/policies/%2F/QUEUE_NAME_policy")
|
43
|
+
.with(basic_auth: ['guest', 'guest'])
|
44
|
+
.with(:body => {
|
45
|
+
"pattern" => "^QUEUE_NAME$",
|
46
|
+
"priority" => 1,
|
47
|
+
"apply-to" => "queues",
|
48
|
+
"definition" => {
|
49
|
+
"dead-letter-routing-key" => "QUEUE_NAME_dead_letter",
|
50
|
+
"dead-letter-exchange" => ""
|
51
|
+
}}.to_json)
|
52
|
+
.to_return(:status => 204)
|
53
|
+
|
54
|
+
@queue_properties.set_queue_policy!(@server, @queue_name, :lazy => false, :dead_lettering => true, :routing_key => "QUEUE_NAME_dead_letter")
|
55
|
+
end
|
56
|
+
|
57
|
+
test "creates a policy by posting to the rabbitmq if lazy queues are enabled" do
|
58
|
+
stub_request(:put, "http://localhost:15672/api/policies/%2F/QUEUE_NAME_policy")
|
59
|
+
.with(basic_auth: ['guest', 'guest'])
|
60
|
+
.with(:body => {
|
61
|
+
"pattern" => "^QUEUE_NAME$",
|
62
|
+
"priority" => 1,
|
63
|
+
"apply-to" => "queues",
|
64
|
+
"definition" => {
|
65
|
+
"queue-mode" => "lazy"
|
66
|
+
}}.to_json)
|
67
|
+
.to_return(:status => 204)
|
68
|
+
|
69
|
+
@queue_properties.set_queue_policy!(@server, @queue_name, :lazy => true, :dead_lettering => false)
|
70
|
+
end
|
71
|
+
|
72
|
+
test "raises exception when policy couldn't successfully be created" do
|
73
|
+
stub_request(:put, "http://localhost:15672/api/policies/%2F/QUEUE_NAME_policy")
|
74
|
+
.with(basic_auth: ['guest', 'guest'])
|
75
|
+
.to_return(:status => [405])
|
76
|
+
|
77
|
+
assert_raises QueueProperties::FailedRabbitRequest do
|
78
|
+
@queue_properties.set_queue_policy!(@server, @queue_name, :lazy => true, :dead_lettering => true)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
test "can optionally specify a message ttl" do
|
83
|
+
stub_request(:put, "http://localhost:15672/api/policies/%2F/QUEUE_NAME_policy")
|
84
|
+
.with(basic_auth: ['guest', 'guest'])
|
85
|
+
.with(:body => {
|
86
|
+
"pattern" => "^QUEUE_NAME$",
|
87
|
+
"priority" => 1,
|
88
|
+
"apply-to" => "queues",
|
89
|
+
"definition" => {
|
90
|
+
"dead-letter-routing-key" => "QUEUE_NAME_dead_letter",
|
91
|
+
"dead-letter-exchange" => "",
|
92
|
+
"message-ttl" => 10000
|
93
|
+
}}.to_json)
|
94
|
+
.to_return(:status => 204)
|
95
|
+
|
96
|
+
@queue_properties.set_queue_policy!(@server, @queue_name, :dead_lettering => true, :message_ttl => 10000, :routing_key => "QUEUE_NAME_dead_letter")
|
97
|
+
end
|
98
|
+
|
99
|
+
test "properly encodes the vhost from the configuration" do
|
100
|
+
stub_request(:put, "http://localhost:15672/api/policies/foo%2F/QUEUE_NAME_policy")
|
101
|
+
.with(basic_auth: ['guest', 'guest'])
|
102
|
+
.with(:body => {
|
103
|
+
"pattern" => "^QUEUE_NAME$",
|
104
|
+
"priority" => 1,
|
105
|
+
"apply-to" => "queues",
|
106
|
+
"definition" => {
|
107
|
+
"dead-letter-routing-key" => "QUEUE_NAME_dead_letter",
|
108
|
+
"dead-letter-exchange" => ""
|
109
|
+
}}.to_json)
|
110
|
+
.to_return(:status => 204)
|
111
|
+
|
112
|
+
@config.vhost = "foo/"
|
113
|
+
|
114
|
+
@queue_properties.set_queue_policy!(@server, @queue_name, :dead_lettering => true, :routing_key => "QUEUE_NAME_dead_letter")
|
115
|
+
end
|
116
|
+
|
117
|
+
test "update_queue_properties! calls remove_obsolete_bindings if bindings are part of the options hash" do
|
118
|
+
bindings = [{:exchange => "foo", :key => "a.b.c"}]
|
119
|
+
options = {
|
120
|
+
:server => "server", :lazy => true, :dead_lettering => true,
|
121
|
+
:queue_name => "QUEUE_NAME", :dead_letter_queue_name => "QUEUE_NAME_dead_letter",
|
122
|
+
:message_ttl => 10000,
|
123
|
+
:bindings => bindings
|
124
|
+
}
|
125
|
+
@queue_properties.expects(:set_queue_policy!).twice
|
126
|
+
@queue_properties.expects(:remove_obsolete_bindings).with("server", "QUEUE_NAME", bindings)
|
127
|
+
@queue_properties.update_queue_properties!(options)
|
128
|
+
end
|
129
|
+
|
130
|
+
test "remove_obsolete_bindings removes an obsolete binding but does not remove the default binding" do
|
131
|
+
bindings = [{:exchange => "foo", :key => "QUEUE_NAME"}, {:exchange => "foo", :key => "a.b.c"}]
|
132
|
+
stub_request(:get, "http://localhost:15672/api/queues/%2F/QUEUE_NAME/bindings")
|
133
|
+
.with(basic_auth: ['guest', 'guest'])
|
134
|
+
.to_return(:status => 200,
|
135
|
+
:body =>[
|
136
|
+
{
|
137
|
+
"destination_type" => "queue",
|
138
|
+
"source" => "",
|
139
|
+
"routing_key" => "QUEUE_NAME",
|
140
|
+
"destination" => "QUEUE_NAME",
|
141
|
+
"vhost" => "/",
|
142
|
+
"properties_key" => "QUEUE_NAME",
|
143
|
+
"arguments" => {}
|
144
|
+
},
|
145
|
+
{
|
146
|
+
"destination_type" => "queue",
|
147
|
+
"source" => "foo",
|
148
|
+
"routing_key" => "QUEUE_NAME",
|
149
|
+
"destination" => "QUEUE_NAME",
|
150
|
+
"vhost" => "/",
|
151
|
+
"properties_key" => "QUEUE_NAME",
|
152
|
+
"arguments" => {}
|
153
|
+
},
|
154
|
+
{
|
155
|
+
"destination_type" => "queue",
|
156
|
+
"source" => "foo",
|
157
|
+
"routing_key" => "a.b.c",
|
158
|
+
"destination" => "QUEUE_NAME",
|
159
|
+
"vhost" => "/",
|
160
|
+
"properties_key" => "a.b.c",
|
161
|
+
"arguments" => {}
|
162
|
+
},
|
163
|
+
{
|
164
|
+
"destination_type" => "queue",
|
165
|
+
"source" => "foofoo",
|
166
|
+
"routing_key" => "x.y.z",
|
167
|
+
"destination" => "QUEUE_NAME",
|
168
|
+
"vhost" => "/",
|
169
|
+
"properties_key" => "x.y.z",
|
170
|
+
"arguments" => {}
|
171
|
+
}
|
172
|
+
].to_json)
|
173
|
+
|
174
|
+
stub_request(:delete, "http://localhost:15672/api/bindings/%2F/e/foofoo/q/QUEUE_NAME/x.y.z")
|
175
|
+
.with(basic_auth: ['guest', 'guest'])
|
176
|
+
.to_return(:status => 200)
|
177
|
+
|
178
|
+
@queue_properties.remove_obsolete_bindings(@server, "QUEUE_NAME", bindings)
|
179
|
+
end
|
180
|
+
|
181
|
+
test "raises an error when bindings cannot be retrieved" do
|
182
|
+
stub_request(:get, "http://localhost:15672/api/queues/%2F/QUEUE_NAME/bindings")
|
183
|
+
.with(basic_auth: ['guest', 'guest'])
|
184
|
+
.to_return(:status => 500)
|
185
|
+
assert_raises(Beetle::QueueProperties::FailedRabbitRequest) { @queue_properties.remove_obsolete_bindings(@server, "QUEUE_NAME", []) }
|
186
|
+
end
|
187
|
+
|
188
|
+
test "raises an error when bindings cannot be deleted" do
|
189
|
+
stub_request(:get, "http://localhost:15672/api/queues/%2F/QUEUE_NAME/bindings")
|
190
|
+
.with(basic_auth: ['guest', 'guest'])
|
191
|
+
.to_return(:status => 200, :body => [
|
192
|
+
{
|
193
|
+
"destination_type" => "queue",
|
194
|
+
"source" => "foofoo",
|
195
|
+
"routing_key" => "x.y.z",
|
196
|
+
"destination" => "QUEUE_NAME",
|
197
|
+
"vhost" => "/",
|
198
|
+
"properties_key" => "x.y.z",
|
199
|
+
"arguments" => {}
|
200
|
+
}
|
201
|
+
].to_json)
|
202
|
+
stub_request(:delete, "http://localhost:15672/api/bindings/%2F/e/foofoo/q/QUEUE_NAME/x.y.z")
|
203
|
+
.with(basic_auth: ['guest', 'guest'])
|
204
|
+
.to_return(:status => 500)
|
205
|
+
|
206
|
+
assert_raises(Beetle::QueueProperties::FailedRabbitRequest) { @queue_properties.remove_obsolete_bindings(@server, "QUEUE_NAME", []) }
|
207
|
+
end
|
208
|
+
|
209
|
+
end
|
210
|
+
end
|
@@ -246,7 +246,7 @@ module Beetle
|
|
246
246
|
@client.config.dead_lettering_enabled = false
|
247
247
|
end
|
248
248
|
|
249
|
-
test "should call reject on the message header when processing the handler returns true on reject? if
|
249
|
+
test "should call reject on the message header when processing the handler returns true on reject? if dead lettering has been enabled" do
|
250
250
|
header = header_with_params({})
|
251
251
|
result = mock("result")
|
252
252
|
result.expects(:reject?).returns(true)
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: beetle
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.0.0
|
4
|
+
version: 3.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Stefan Kaes
|
@@ -12,7 +12,7 @@ authors:
|
|
12
12
|
autorequire:
|
13
13
|
bindir: bin
|
14
14
|
cert_chain: []
|
15
|
-
date: 2019-05-
|
15
|
+
date: 2019-05-27 00:00:00.000000000 Z
|
16
16
|
dependencies:
|
17
17
|
- !ruby/object:Gem::Dependency
|
18
18
|
name: bunny
|
@@ -327,6 +327,7 @@ files:
|
|
327
327
|
- examples/redundant.rb
|
328
328
|
- examples/rpc.rb
|
329
329
|
- examples/simple.rb
|
330
|
+
- examples/throttling.rb
|
330
331
|
- features/redis_auto_failover.feature
|
331
332
|
- features/step_definitions/redis_auto_failover_steps.rb
|
332
333
|
- features/support/beetle_handler
|
@@ -340,12 +341,12 @@ files:
|
|
340
341
|
- lib/beetle/base.rb
|
341
342
|
- lib/beetle/client.rb
|
342
343
|
- lib/beetle/configuration.rb
|
343
|
-
- lib/beetle/dead_lettering.rb
|
344
344
|
- lib/beetle/deduplication_store.rb
|
345
345
|
- lib/beetle/handler.rb
|
346
346
|
- lib/beetle/logging.rb
|
347
347
|
- lib/beetle/message.rb
|
348
348
|
- lib/beetle/publisher.rb
|
349
|
+
- lib/beetle/queue_properties.rb
|
349
350
|
- lib/beetle/r_c.rb
|
350
351
|
- lib/beetle/redis_ext.rb
|
351
352
|
- lib/beetle/subscriber.rb
|
@@ -357,12 +358,12 @@ files:
|
|
357
358
|
- test/beetle/beetle_test.rb
|
358
359
|
- test/beetle/client_test.rb
|
359
360
|
- test/beetle/configuration_test.rb
|
360
|
-
- test/beetle/dead_lettering_test.rb
|
361
361
|
- test/beetle/deduplication_store_test.rb
|
362
362
|
- test/beetle/handler_test.rb
|
363
363
|
- test/beetle/message/settings_test.rb
|
364
364
|
- test/beetle/message_test.rb
|
365
365
|
- test/beetle/publisher_test.rb
|
366
|
+
- test/beetle/queue_properties_test.rb
|
366
367
|
- test/beetle/r_c_test.rb
|
367
368
|
- test/beetle/redis_ext_test.rb
|
368
369
|
- test/beetle/subscriber_test.rb
|
@@ -397,13 +398,13 @@ test_files:
|
|
397
398
|
- test/beetle/client_test.rb
|
398
399
|
- test/beetle/amqp_gem_behavior_test.rb
|
399
400
|
- test/beetle/deduplication_store_test.rb
|
401
|
+
- test/beetle/queue_properties_test.rb
|
400
402
|
- test/beetle/handler_test.rb
|
401
403
|
- test/beetle/beetle_test.rb
|
402
404
|
- test/beetle/configuration_test.rb
|
403
405
|
- test/beetle/subscriber_test.rb
|
404
406
|
- test/beetle/message/settings_test.rb
|
405
407
|
- test/beetle/redis_ext_test.rb
|
406
|
-
- test/beetle/dead_lettering_test.rb
|
407
408
|
- test/beetle/message_test.rb
|
408
409
|
- test/beetle/publisher_test.rb
|
409
410
|
- test/beetle/r_c_test.rb
|
@@ -1,117 +0,0 @@
|
|
1
|
-
require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
|
2
|
-
|
3
|
-
module Beetle
|
4
|
-
class SetDeadLetterPolicyTest < Minitest::Test
|
5
|
-
def setup
|
6
|
-
@server = "localhost:15672"
|
7
|
-
@queue_name = "QUEUE_NAME"
|
8
|
-
@config = Configuration.new
|
9
|
-
@config.logger = Logger.new("/dev/null")
|
10
|
-
@dead_lettering = DeadLettering.new(@config)
|
11
|
-
end
|
12
|
-
|
13
|
-
test "raises exception when queue name wasn't specified" do
|
14
|
-
assert_raises ArgumentError do
|
15
|
-
@dead_lettering.set_queue_policy!(@server, "")
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
|
-
test "raises exception when no server was specified" do
|
20
|
-
assert_raises ArgumentError do
|
21
|
-
@dead_lettering.set_queue_policy!("", @queue_name)
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
test "set_queue_policies! calls set_queue_policy for both target queue and dead letter queue" do
|
26
|
-
options = {
|
27
|
-
:server => "server", :lazy => true, :dead_lettering => true,
|
28
|
-
:queue_name => "QUEUE_NAME", :dead_letter_queue_name => "QUEUE_NAME_dead_letter",
|
29
|
-
:message_ttl => 10000
|
30
|
-
}
|
31
|
-
@dead_lettering.expects(:set_queue_policy!).with("server", "QUEUE_NAME",
|
32
|
-
:lazy => true, :dead_lettering => true,
|
33
|
-
:routing_key => "QUEUE_NAME_dead_letter")
|
34
|
-
@dead_lettering.expects(:set_queue_policy!).with("server", "QUEUE_NAME_dead_letter",
|
35
|
-
:lazy => true, :dead_lettering => true,
|
36
|
-
:routing_key => "QUEUE_NAME",
|
37
|
-
:message_ttl => 10000)
|
38
|
-
@dead_lettering.set_queue_policies!(options)
|
39
|
-
end
|
40
|
-
|
41
|
-
test "creates a policy by posting to the rabbitmq if dead lettering is enabled" do
|
42
|
-
stub_request(:put, "http://localhost:15672/api/policies/%2F/QUEUE_NAME_policy")
|
43
|
-
.with(basic_auth: ['guest', 'guest'])
|
44
|
-
.with(:body => {
|
45
|
-
"pattern" => "^QUEUE_NAME$",
|
46
|
-
"priority" => 1,
|
47
|
-
"apply-to" => "queues",
|
48
|
-
"definition" => {
|
49
|
-
"dead-letter-routing-key" => "QUEUE_NAME_dead_letter",
|
50
|
-
"dead-letter-exchange" => ""
|
51
|
-
}}.to_json)
|
52
|
-
.to_return(:status => 204)
|
53
|
-
|
54
|
-
@dead_lettering.set_queue_policy!(@server, @queue_name, :lazy => false, :dead_lettering => true, :routing_key => "QUEUE_NAME_dead_letter")
|
55
|
-
end
|
56
|
-
|
57
|
-
test "creates a policy by posting to the rabbitmq if lazy queues are enabled" do
|
58
|
-
stub_request(:put, "http://localhost:15672/api/policies/%2F/QUEUE_NAME_policy")
|
59
|
-
.with(basic_auth: ['guest', 'guest'])
|
60
|
-
.with(:body => {
|
61
|
-
"pattern" => "^QUEUE_NAME$",
|
62
|
-
"priority" => 1,
|
63
|
-
"apply-to" => "queues",
|
64
|
-
"definition" => {
|
65
|
-
"queue-mode" => "lazy"
|
66
|
-
}}.to_json)
|
67
|
-
.to_return(:status => 204)
|
68
|
-
|
69
|
-
@dead_lettering.set_queue_policy!(@server, @queue_name, :lazy => true, :dead_lettering => false)
|
70
|
-
end
|
71
|
-
|
72
|
-
test "raises exception when policy couldn't successfully be created" do
|
73
|
-
stub_request(:put, "http://localhost:15672/api/policies/%2F/QUEUE_NAME_policy")
|
74
|
-
.with(basic_auth: ['guest', 'guest'])
|
75
|
-
.to_return(:status => [405])
|
76
|
-
|
77
|
-
assert_raises DeadLettering::FailedRabbitRequest do
|
78
|
-
@dead_lettering.set_queue_policy!(@server, @queue_name, :lazy => true, :dead_lettering => true)
|
79
|
-
end
|
80
|
-
end
|
81
|
-
|
82
|
-
test "can optionally specify a message ttl" do
|
83
|
-
stub_request(:put, "http://localhost:15672/api/policies/%2F/QUEUE_NAME_policy")
|
84
|
-
.with(basic_auth: ['guest', 'guest'])
|
85
|
-
.with(:body => {
|
86
|
-
"pattern" => "^QUEUE_NAME$",
|
87
|
-
"priority" => 1,
|
88
|
-
"apply-to" => "queues",
|
89
|
-
"definition" => {
|
90
|
-
"dead-letter-routing-key" => "QUEUE_NAME_dead_letter",
|
91
|
-
"dead-letter-exchange" => "",
|
92
|
-
"message-ttl" => 10000
|
93
|
-
}}.to_json)
|
94
|
-
.to_return(:status => 204)
|
95
|
-
|
96
|
-
@dead_lettering.set_queue_policy!(@server, @queue_name, :dead_lettering => true, :message_ttl => 10000, :routing_key => "QUEUE_NAME_dead_letter")
|
97
|
-
end
|
98
|
-
|
99
|
-
test "properly encodes the vhost from the configuration" do
|
100
|
-
stub_request(:put, "http://localhost:15672/api/policies/foo%2F/QUEUE_NAME_policy")
|
101
|
-
.with(basic_auth: ['guest', 'guest'])
|
102
|
-
.with(:body => {
|
103
|
-
"pattern" => "^QUEUE_NAME$",
|
104
|
-
"priority" => 1,
|
105
|
-
"apply-to" => "queues",
|
106
|
-
"definition" => {
|
107
|
-
"dead-letter-routing-key" => "QUEUE_NAME_dead_letter",
|
108
|
-
"dead-letter-exchange" => ""
|
109
|
-
}}.to_json)
|
110
|
-
.to_return(:status => 204)
|
111
|
-
|
112
|
-
@config.vhost = "foo/"
|
113
|
-
|
114
|
-
@dead_lettering.set_queue_policy!(@server, @queue_name, :dead_lettering => true, :routing_key => "QUEUE_NAME_dead_letter")
|
115
|
-
end
|
116
|
-
end
|
117
|
-
end
|