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