beetle 3.0.0.rc1 → 3.0.0.rc2
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 +10 -1
- data/features/step_definitions/redis_auto_failover_steps.rb +1 -1
- data/features/support/beetle_handler +10 -1
- data/lib/beetle/base.rb +32 -11
- data/lib/beetle/client.rb +16 -5
- data/lib/beetle/configuration.rb +11 -0
- data/lib/beetle/dead_lettering.rb +26 -41
- data/lib/beetle/publisher.rb +3 -4
- data/lib/beetle/subscriber.rb +8 -10
- data/lib/beetle/version.rb +1 -1
- data/test/beetle/base_test.rb +50 -0
- data/test/beetle/client_test.rb +13 -14
- data/test/beetle/dead_lettering_test.rb +20 -60
- data/test/beetle/publisher_test.rb +4 -36
- data/test/beetle/subscriber_test.rb +12 -22
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fb0489f8580ec11b65b79718c9e76c0f4b26a14af2fbbf471cf4b630fca5fa7d
|
4
|
+
data.tar.gz: 0f3ef313bfaf103eecfd1c1714c5d28b6ec10bc7ce0313e55f0cee6e00f2086a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 51aa8c7058c8149daa6c2d69c1ae8a26731957290f06e4bde26a06613e260030f9cb16d286415958db74afcb38bdc74a9ccacc58643ceb25227662a800fada22
|
7
|
+
data.tar.gz: ae1eed22b04f81c612aff1ad88836e57df2db997a923da8f1819d8675093a9533f377e6429928049f9665b5a7548cdbbfb48172ddfbb361bac2e2adbcfba507b
|
data/RELEASE_NOTES.rdoc
CHANGED
@@ -1,12 +1,21 @@
|
|
1
1
|
= Release Notes
|
2
2
|
|
3
|
+
== Version 3.0.0.rc2
|
4
|
+
* change policy setup to be asynchronous, on demand in publisher and
|
5
|
+
consumer. Users have to run a processors to listen to messages and
|
6
|
+
call setup_queue_policies! with the parses JSON paylod of the
|
7
|
+
message.
|
8
|
+
* added dump_expiries command to beetle to dump dediplication store
|
9
|
+
expiry times.
|
10
|
+
* added delete_queue_keys command to beetle to allow deletion of
|
11
|
+
excess dedup store entries for a given queue.
|
3
12
|
|
4
13
|
== Version 3.0.0.rc1
|
5
14
|
* provide client method to setup queues and queue policies.
|
6
15
|
Setting up queue policies on demand in publisher and subscriber is OK
|
7
16
|
for a small number of queues, publishers and subscribers. But the HTTP
|
8
17
|
API of RabbitMQ doesn't scale all that well, so that a large number
|
9
|
-
of
|
18
|
+
of HTTP calls to set up queue policies can in fact crash a server.
|
10
19
|
|
11
20
|
== Version 2.3.2
|
12
21
|
* config server: fixed a race condition when accessing server state.
|
@@ -144,7 +144,7 @@ Then /^the redis master of the beetle handler should be "([^\"]*)"$/ do |redis_n
|
|
144
144
|
Beetle.config.servers = "127.0.0.1:5672" # rabbitmq
|
145
145
|
Beetle.config.logger.level = Logger::INFO
|
146
146
|
client = Beetle::Client.new.configure :auto_delete => true do |config|
|
147
|
-
config.queue(:echo)
|
147
|
+
config.queue(:echo, :lazy => true, :dead_lettering => true)
|
148
148
|
config.message(:echo)
|
149
149
|
end
|
150
150
|
assert_match /#{TestDaemons::Redis[redis_name].ip_with_port}/, client.rpc(:echo, 'nil').second
|
@@ -3,6 +3,7 @@
|
|
3
3
|
require "rubygems"
|
4
4
|
require "daemons"
|
5
5
|
require "optparse"
|
6
|
+
require 'json'
|
6
7
|
require File.expand_path("../../lib/beetle", File.dirname(__FILE__))
|
7
8
|
|
8
9
|
tmp_path = File.expand_path("../../tmp", File.dirname(__FILE__))
|
@@ -22,7 +23,7 @@ Daemons.run_proc("beetle_handler", :log_output => true, :dir_mode => :normal, :d
|
|
22
23
|
Beetle.config.logger.level = Logger::INFO
|
23
24
|
|
24
25
|
client = Beetle::Client.new.configure :auto_delete => true do |config|
|
25
|
-
config.queue(:echo)
|
26
|
+
config.queue(:echo, :lazy => true, :dead_lettering => true)
|
26
27
|
config.message(:echo)
|
27
28
|
config.handler(:echo) do |message|
|
28
29
|
begin
|
@@ -32,6 +33,14 @@ Daemons.run_proc("beetle_handler", :log_output => true, :dir_mode => :normal, :d
|
|
32
33
|
"no redis master: exception: #{$!.class}(#{$!}), master_file: '#{master_file_content}'"
|
33
34
|
end
|
34
35
|
end
|
36
|
+
config.handler(Beetle.config.beetle_policy_updates_queue_name) do |message|
|
37
|
+
begin
|
38
|
+
Beetle.config.logger.info "received beetle policy update message': #{message.data}"
|
39
|
+
client.set_queue_policies!(JSON.parse(message.data))
|
40
|
+
rescue => e
|
41
|
+
Beetle.config.logger.error("#{e}:#{e.backtrace.join("\n")}")
|
42
|
+
end
|
43
|
+
end
|
35
44
|
end
|
36
45
|
client.listen do
|
37
46
|
puts "Started beetle handler for system: #{Beetle.config.system_name}"
|
data/lib/beetle/base.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'json'
|
2
|
+
|
1
3
|
module Beetle
|
2
4
|
# Abstract base class shared by Publisher and Subscriber
|
3
5
|
class Base
|
@@ -12,7 +14,6 @@ module Beetle
|
|
12
14
|
@server = @servers[rand @servers.size]
|
13
15
|
@exchanges = {}
|
14
16
|
@queues = {}
|
15
|
-
@dead_lettering = DeadLettering.new(@client)
|
16
17
|
end
|
17
18
|
|
18
19
|
private
|
@@ -54,13 +55,7 @@ module Beetle
|
|
54
55
|
@queues[@server] ||= {}
|
55
56
|
end
|
56
57
|
|
57
|
-
|
58
|
-
|
59
|
-
def queue(name, create_policies: false)
|
60
|
-
info = queues[name]
|
61
|
-
if info && create_policies && !info.create_policies
|
62
|
-
queues.delete(name)
|
63
|
-
end
|
58
|
+
def queue(name)
|
64
59
|
queues[name] ||=
|
65
60
|
begin
|
66
61
|
opts = @client.queues[name]
|
@@ -72,11 +67,37 @@ module Beetle
|
|
72
67
|
@client.bindings[name].each do |binding_options|
|
73
68
|
exchange_name = binding_options[:exchange]
|
74
69
|
binding_options = binding_options.slice(*QUEUE_BINDING_KEYS)
|
75
|
-
the_queue = bind_queue!(queue_name, creation_options, exchange_name, binding_options
|
70
|
+
the_queue = bind_queue!(queue_name, creation_options, exchange_name, binding_options)
|
76
71
|
end
|
77
|
-
|
72
|
+
the_queue
|
78
73
|
end
|
79
|
-
|
74
|
+
end
|
75
|
+
|
76
|
+
def bind_dead_letter_queue!(channel, target_queue, creation_keys = {})
|
77
|
+
policy_options = @client.queues[target_queue].slice(:dead_lettering, :lazy)
|
78
|
+
dead_letter_queue_name = "#{target_queue}_dead_letter"
|
79
|
+
if policy_options[:dead_lettering]
|
80
|
+
logger.debug("Beetle: creating dead letter queue #{dead_letter_queue_name} with opts: #{creation_keys.inspect}")
|
81
|
+
channel.queue(dead_letter_queue_name, creation_keys)
|
82
|
+
end
|
83
|
+
return {
|
84
|
+
:queue_name => target_queue,
|
85
|
+
:dead_letter_queue_name => dead_letter_queue_name,
|
86
|
+
:message_ttl => @client.config.dead_lettering_msg_ttl,
|
87
|
+
}.merge(policy_options)
|
88
|
+
end
|
89
|
+
|
90
|
+
# called by <tt>bind_queue!</tt>
|
91
|
+
def publish_policy_options(options)
|
92
|
+
# avoid endless recursion
|
93
|
+
return if options[:queue_name] == @client.config.beetle_policy_updates_queue_name
|
94
|
+
payload = options.merge(:server => @server)
|
95
|
+
logger.debug("Beetle: publishing policy options on #{@server}: #{payload.inspect}")
|
96
|
+
# make sure to declare the queue, so the message does not get lost
|
97
|
+
queue(@client.config.beetle_policy_updates_queue_name)
|
98
|
+
data = payload.to_json
|
99
|
+
opts = Message.publishing_options(:key => @client.config.beetle_policy_updates_routing_key, :persistent => true, :redundant => false)
|
100
|
+
exchange(@client.config.beetle_policy_exchange_name).publish(data, opts)
|
80
101
|
end
|
81
102
|
|
82
103
|
end
|
data/lib/beetle/client.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'json'
|
2
|
+
|
1
3
|
module Beetle
|
2
4
|
# This class provides the interface through which messaging is configured for both
|
3
5
|
# message producers and consumers. It keeps references to an instance of a
|
@@ -53,7 +55,17 @@ module Beetle
|
|
53
55
|
@messages = {}
|
54
56
|
@bindings = {}
|
55
57
|
@deduplication_store = DeduplicationStore.new(config)
|
58
|
+
@dead_lettering = DeadLettering.new(config)
|
56
59
|
load_brokers_from_config
|
60
|
+
register_exchange(config.beetle_policy_exchange_name)
|
61
|
+
# make sure dead lettering is false for the policy update queue
|
62
|
+
register_queue(
|
63
|
+
config.beetle_policy_updates_queue_name,
|
64
|
+
:exchange => config.beetle_policy_exchange_name,
|
65
|
+
:key => config.beetle_policy_updates_routing_key,
|
66
|
+
:dead_lettering => false,
|
67
|
+
:lazy => false,
|
68
|
+
)
|
57
69
|
end
|
58
70
|
|
59
71
|
# register an exchange with the given _name_ and a set of _options_:
|
@@ -209,11 +221,6 @@ module Beetle
|
|
209
221
|
publisher.purge(queues)
|
210
222
|
end
|
211
223
|
|
212
|
-
# declares all queues, binds them and creates/updates all policies
|
213
|
-
def setup_queues_and_policies(queues)
|
214
|
-
publisher.setup_queues_and_policies(queues)
|
215
|
-
end
|
216
|
-
|
217
224
|
# start listening to all registered queues. Calls #listen_queues internally
|
218
225
|
# runs the given block before entering the eventmachine loop.
|
219
226
|
def listen(_deprecated_messages=nil, &block)
|
@@ -292,6 +299,10 @@ module Beetle
|
|
292
299
|
@subscriber = nil
|
293
300
|
end
|
294
301
|
|
302
|
+
def set_queue_policies!(message_payload)
|
303
|
+
@dead_lettering.set_queue_policies!(message_payload)
|
304
|
+
end
|
305
|
+
|
295
306
|
private
|
296
307
|
|
297
308
|
def determine_queue_names(queues)
|
data/lib/beetle/configuration.rb
CHANGED
@@ -5,6 +5,14 @@ module Beetle
|
|
5
5
|
class Configuration
|
6
6
|
# system name (used for redis cluster partitioning) (defaults to <tt>system</tt>)
|
7
7
|
attr_accessor :system_name
|
8
|
+
# system_exchange_name is the name of the exchange on which to publish system internal messages, such as
|
9
|
+
# messages to set up queue policies. Whenever a queue is declared in the client, either by publisher or
|
10
|
+
# consumer, a message with the queue policy parameters is sent to this exachange. (defaults to <tt>beetle</tt>)
|
11
|
+
attr_accessor :beetle_policy_exchange_name
|
12
|
+
# Name of the policy update queue
|
13
|
+
attr_accessor :beetle_policy_updates_queue_name
|
14
|
+
# Name of the policy update routing key
|
15
|
+
attr_accessor :beetle_policy_updates_routing_key
|
8
16
|
# default logger (defaults to <tt>Logger.new(log_file)</tt>)
|
9
17
|
attr_accessor :logger
|
10
18
|
# defaults to <tt>STDOUT</tt>
|
@@ -120,6 +128,9 @@ module Beetle
|
|
120
128
|
|
121
129
|
def initialize #:nodoc:
|
122
130
|
self.system_name = "system"
|
131
|
+
self.beetle_policy_exchange_name = "beetle-policies"
|
132
|
+
self.beetle_policy_updates_queue_name = "beetle-policy-updates"
|
133
|
+
self.beetle_policy_updates_routing_key = "beetle.policy.update"
|
123
134
|
|
124
135
|
self.gc_threshold = 1.hour.to_i
|
125
136
|
self.redis_server = "localhost:6379"
|
@@ -5,56 +5,44 @@ module Beetle
|
|
5
5
|
class DeadLettering
|
6
6
|
class FailedRabbitRequest < StandardError; end
|
7
7
|
|
8
|
-
attr_reader :
|
8
|
+
attr_reader :config
|
9
9
|
|
10
|
-
def initialize(
|
11
|
-
@
|
12
|
-
@config = client.config
|
10
|
+
def initialize(config)
|
11
|
+
@config = config
|
13
12
|
end
|
14
13
|
|
15
|
-
def
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
14
|
+
def set_queue_policies!(options)
|
15
|
+
# logger.debug "Setting queue policies: #{options.inspect}"
|
16
|
+
options = options.symbolize_keys
|
17
|
+
server = options[:server]
|
18
|
+
target_queue = options[:queue_name]
|
19
|
+
dead_letter_queue_name = options[:dead_letter_queue_name]
|
20
|
+
policy_options = options.slice(:lazy, :dead_lettering)
|
22
21
|
|
23
|
-
|
24
|
-
|
25
|
-
end
|
26
|
-
set_queue_policies!(servers, target_queue, policy_options)
|
27
|
-
|
28
|
-
if policy_options[:dead_lettering]
|
29
|
-
logger.info("Beetle: setting #{target_queue} as dead letter queue of #{dead_letter_queue_name} on all servers")
|
30
|
-
set_queue_policies!(
|
31
|
-
servers,
|
32
|
-
dead_letter_queue_name,
|
33
|
-
{ :message_ttl => config.dead_lettering_msg_ttl,
|
34
|
-
:routing_key => target_queue
|
35
|
-
}.merge(policy_options)
|
36
|
-
)
|
37
|
-
end
|
38
|
-
end
|
22
|
+
target_queue_options = policy_options.merge(:routing_key => dead_letter_queue_name)
|
23
|
+
set_queue_policy!(server, target_queue, target_queue_options)
|
39
24
|
|
40
|
-
|
41
|
-
|
25
|
+
dead_letter_queue_options = policy_options.merge(:routing_key => target_queue, :message_ttl => options[:message_ttl])
|
26
|
+
set_queue_policy!(server, dead_letter_queue_name, dead_letter_queue_options)
|
42
27
|
end
|
43
28
|
|
44
29
|
def set_queue_policy!(server, queue_name, options={})
|
30
|
+
logger.info "Setting queue policy: #{server}, #{queue_name}, #{options.inspect}"
|
31
|
+
|
45
32
|
raise ArgumentError.new("server missing") if server.blank?
|
46
33
|
raise ArgumentError.new("queue name missing") if queue_name.blank?
|
47
34
|
|
48
35
|
return unless options[:dead_lettering] || options[:lazy]
|
49
36
|
|
50
37
|
vhost = CGI.escape(config.vhost)
|
38
|
+
# no need to worry that the server has the port 5672. Net:HTTP will take care of this. See below.
|
51
39
|
request_url = URI("http://#{server}/api/policies/#{vhost}/#{queue_name}_policy")
|
52
40
|
request = Net::HTTP::Put.new(request_url)
|
53
41
|
|
54
42
|
# set up queue policy
|
55
43
|
definition = {}
|
56
44
|
if options[:dead_lettering]
|
57
|
-
definition["dead-letter-routing-key"] =
|
45
|
+
definition["dead-letter-routing-key"] = options[:routing_key]
|
58
46
|
definition["dead-letter-exchange"] = ""
|
59
47
|
definition["message-ttl"] = options[:message_ttl] if options[:message_ttl]
|
60
48
|
end
|
@@ -80,19 +68,15 @@ module Beetle
|
|
80
68
|
:ok
|
81
69
|
end
|
82
70
|
|
83
|
-
def dead_letter_routing_key(queue_name, options)
|
84
|
-
options.fetch(:routing_key) { dead_letter_queue_name(queue_name) }
|
85
|
-
end
|
86
|
-
|
87
|
-
def dead_letter_queue_name(queue_name)
|
88
|
-
"#{queue_name}_dead_letter"
|
89
|
-
end
|
90
|
-
|
91
71
|
def run_rabbit_http_request(uri, request, &block)
|
92
72
|
request.basic_auth(config.user, config.password)
|
93
73
|
request["Content-Type"] = "application/json"
|
94
|
-
Net::HTTP.
|
95
|
-
|
74
|
+
http = Net::HTTP.new(uri.hostname, config.api_port)
|
75
|
+
http.read_timeout = config.dead_lettering_read_timeout
|
76
|
+
# don't do this in production:
|
77
|
+
# http.set_debug_output(logger.instance_eval{ @logdev.dev })
|
78
|
+
http.start do |instance|
|
79
|
+
block.call(instance) if block_given?
|
96
80
|
end
|
97
81
|
end
|
98
82
|
|
@@ -103,7 +87,8 @@ module Beetle
|
|
103
87
|
end
|
104
88
|
|
105
89
|
def logger
|
106
|
-
config.logger
|
90
|
+
@config.logger
|
107
91
|
end
|
92
|
+
|
108
93
|
end
|
109
94
|
end
|
data/lib/beetle/publisher.rb
CHANGED
@@ -222,14 +222,13 @@ module Beetle
|
|
222
222
|
end
|
223
223
|
|
224
224
|
# TODO: Refactor, fetch the keys and stuff itself
|
225
|
-
def bind_queue!(queue_name, creation_keys, exchange_name, binding_keys
|
225
|
+
def bind_queue!(queue_name, creation_keys, exchange_name, binding_keys)
|
226
226
|
logger.debug("Beetle: creating queue with opts: #{creation_keys.inspect}")
|
227
227
|
queue = bunny.queue(queue_name, creation_keys)
|
228
|
-
if create_policies
|
229
|
-
@dead_lettering.bind_dead_letter_queues!(bunny, @client.servers, queue_name, creation_keys)
|
230
|
-
end
|
231
228
|
logger.debug("Beetle: binding queue #{queue_name} to #{exchange_name} with opts: #{binding_keys.inspect}")
|
232
229
|
queue.bind(exchange(exchange_name), binding_keys)
|
230
|
+
policy_options = bind_dead_letter_queue!(bunny, queue_name, creation_keys)
|
231
|
+
publish_policy_options(policy_options)
|
233
232
|
queue
|
234
233
|
end
|
235
234
|
|
data/lib/beetle/subscriber.rb
CHANGED
@@ -144,19 +144,19 @@ module Beetle
|
|
144
144
|
callback = create_subscription_callback(queue_name, amqp_queue_name, handler, opts)
|
145
145
|
keys = opts.slice(*SUBSCRIPTION_KEYS).merge(:key => "#", :ack => true)
|
146
146
|
logger.debug "Beetle: subscribing to queue #{amqp_queue_name} with key # on server #{@server}"
|
147
|
-
queues[queue_name].
|
147
|
+
queues[queue_name].subscribe(keys, &callback)
|
148
148
|
subscriptions[queue_name] = [keys, callback]
|
149
149
|
end
|
150
150
|
|
151
151
|
def pause(queue_name)
|
152
|
-
return unless queues[queue_name].
|
153
|
-
queues[queue_name].
|
152
|
+
return unless queues[queue_name].subscribed?
|
153
|
+
queues[queue_name].unsubscribe
|
154
154
|
end
|
155
155
|
|
156
156
|
def resume(queue_name)
|
157
|
-
return if queues[queue_name].
|
157
|
+
return if queues[queue_name].subscribed?
|
158
158
|
keys, callback = subscriptions[queue_name]
|
159
|
-
queues[queue_name].
|
159
|
+
queues[queue_name].subscribe(keys, &callback)
|
160
160
|
end
|
161
161
|
|
162
162
|
def create_subscription_callback(queue_name, amqp_queue_name, handler, opts)
|
@@ -204,12 +204,10 @@ module Beetle
|
|
204
204
|
channel.__send__(opts[:type], name, opts.slice(*EXCHANGE_CREATION_KEYS))
|
205
205
|
end
|
206
206
|
|
207
|
-
def bind_queue!(queue_name, creation_keys, exchange_name, binding_keys
|
207
|
+
def bind_queue!(queue_name, creation_keys, exchange_name, binding_keys)
|
208
208
|
queue = channel.queue(queue_name, creation_keys)
|
209
|
-
|
210
|
-
|
211
|
-
@dead_lettering.bind_dead_letter_queues!(channel, target_servers, queue_name, creation_keys)
|
212
|
-
end
|
209
|
+
policy_options = bind_dead_letter_queue!(channel, queue_name, creation_keys)
|
210
|
+
publish_policy_options(policy_options)
|
213
211
|
exchange = exchange(exchange_name)
|
214
212
|
queue.bind(exchange, binding_keys)
|
215
213
|
queue
|
data/lib/beetle/version.rb
CHANGED
data/test/beetle/base_test.rb
CHANGED
@@ -53,4 +53,54 @@ module Beetle
|
|
53
53
|
assert_equal "goofy:123", @bs.send(:server_from_settings, {:host => "goofy", :port => 123})
|
54
54
|
end
|
55
55
|
end
|
56
|
+
|
57
|
+
class BindDeadLetterQueuesTest < Minitest::Test
|
58
|
+
def setup
|
59
|
+
@queue_name = "QUEUE_NAME"
|
60
|
+
@config = Configuration.new
|
61
|
+
@client = Client.new @config
|
62
|
+
@bs = Base.new(@client)
|
63
|
+
@config.logger = Logger.new("/dev/null")
|
64
|
+
end
|
65
|
+
|
66
|
+
test "it does not call out to rabbit if neither dead lettering nor lazy queues are enabled" do
|
67
|
+
@client.register_queue(@queue_name, :dead_lettering => false, :lazy => false)
|
68
|
+
channel = stub('channel')
|
69
|
+
expected_options = {
|
70
|
+
:queue_name => "QUEUE_NAME",
|
71
|
+
:dead_letter_queue_name=>"QUEUE_NAME_dead_letter",
|
72
|
+
:message_ttl => 1000,
|
73
|
+
:dead_lettering => false,
|
74
|
+
:lazy => false
|
75
|
+
}
|
76
|
+
assert_equal expected_options, @bs.__send__(:bind_dead_letter_queue!, channel, @queue_name)
|
77
|
+
end
|
78
|
+
|
79
|
+
test "creates and connects the dead letter queue via policies when enabled" do
|
80
|
+
@client.register_queue(@queue_name, :dead_lettering => true, :lazy => true)
|
81
|
+
|
82
|
+
channel = stub('channel')
|
83
|
+
channel.expects(:queue).with("#{@queue_name}_dead_letter", {})
|
84
|
+
|
85
|
+
expected_options = {
|
86
|
+
:queue_name => "QUEUE_NAME",
|
87
|
+
:dead_letter_queue_name=>"QUEUE_NAME_dead_letter",
|
88
|
+
:message_ttl => 1000,
|
89
|
+
:dead_lettering => true,
|
90
|
+
:lazy => true
|
91
|
+
}
|
92
|
+
assert_equal expected_options, @bs.__send__(:bind_dead_letter_queue!, channel, @queue_name)
|
93
|
+
end
|
94
|
+
|
95
|
+
test "publish_policy_options declares the beetle policy updates queue and publishes the options" do
|
96
|
+
options = { :lazy => true, :dead_lettering => true }
|
97
|
+
@bs.logger.stubs(:debug)
|
98
|
+
@bs.expects(:queue).with(@client.config.beetle_policy_updates_queue_name)
|
99
|
+
exchange = mock("exchange")
|
100
|
+
exchange.expects(:publish)
|
101
|
+
@bs.expects(:exchange).with(@client.config.beetle_policy_exchange_name).returns(exchange)
|
102
|
+
@bs.__send__(:publish_policy_options, options)
|
103
|
+
end
|
104
|
+
|
105
|
+
end
|
56
106
|
end
|
data/test/beetle/client_test.rb
CHANGED
@@ -15,20 +15,20 @@ module Beetle
|
|
15
15
|
assert_equal [], @client.additional_subscription_servers
|
16
16
|
end
|
17
17
|
|
18
|
-
test "should have
|
19
|
-
|
18
|
+
test "should have only the system exchange" do
|
19
|
+
assert_equal ["beetle-policies"], @client.exchanges.keys
|
20
20
|
end
|
21
21
|
|
22
|
-
test "should have
|
23
|
-
|
22
|
+
test "should have only the beetle policy queue" do
|
23
|
+
assert_equal ["beetle-policy-updates"], @client.queues.keys
|
24
24
|
end
|
25
25
|
|
26
26
|
test "should have no messages" do
|
27
|
-
|
27
|
+
assert_equal [], @client.messages.keys
|
28
28
|
end
|
29
29
|
|
30
|
-
test "should have
|
31
|
-
|
30
|
+
test "should have only one binding for the beetle policy updates" do
|
31
|
+
assert_equal ["beetle-policy-updates"], @client.bindings.keys
|
32
32
|
end
|
33
33
|
end
|
34
34
|
|
@@ -308,13 +308,6 @@ module Beetle
|
|
308
308
|
assert_equal "ha!", client.purge(:queue1, :queue2)
|
309
309
|
end
|
310
310
|
|
311
|
-
test "should delegate queue setup to the publisher instance" do
|
312
|
-
client = Client.new
|
313
|
-
client.register_queue(:queue)
|
314
|
-
client.send(:publisher).expects(:setup_queues_and_policies).with(["queue"]).returns("ha!")
|
315
|
-
assert_equal "ha!", client.setup_queues_and_policies(["queue"])
|
316
|
-
end
|
317
|
-
|
318
311
|
test "should delegate rpc calls to the publisher instance" do
|
319
312
|
client = Client.new
|
320
313
|
client.register_message("deadletter")
|
@@ -363,6 +356,12 @@ module Beetle
|
|
363
356
|
client.stop_listening
|
364
357
|
end
|
365
358
|
|
359
|
+
test "should delegate set_queue_policies! to the dead lettering instance" do
|
360
|
+
client = Client.new
|
361
|
+
client.instance_variable_get(:@dead_lettering).expects(:set_queue_policies!)
|
362
|
+
client.set_queue_policies!({})
|
363
|
+
end
|
364
|
+
|
366
365
|
test "should delegate pause_listening to the subscriber instance" do
|
367
366
|
client = Client.new
|
368
367
|
client.register_queue(:test)
|
@@ -1,34 +1,13 @@
|
|
1
1
|
require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
|
2
2
|
|
3
3
|
module Beetle
|
4
|
-
class SetDeadLetteringsTest < Minitest::Test
|
5
|
-
def setup
|
6
|
-
@config = Configuration.new
|
7
|
-
@client = Client.new @config
|
8
|
-
@dead_lettering = DeadLettering.new(@client)
|
9
|
-
@config.dead_lettering_enabled = true
|
10
|
-
end
|
11
|
-
|
12
|
-
test "creates a dead letter queue for each server" do
|
13
|
-
servers = %w(a b)
|
14
|
-
|
15
|
-
@dead_lettering.expects(:set_queue_policy!).
|
16
|
-
with("a", "QUEUE_NAME", :message_ttl => 10000)
|
17
|
-
@dead_lettering.expects(:set_queue_policy!).
|
18
|
-
with("b", "QUEUE_NAME", :message_ttl => 10000)
|
19
|
-
|
20
|
-
@dead_lettering.set_queue_policies!(servers, "QUEUE_NAME", :message_ttl => 10000)
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
4
|
class SetDeadLetterPolicyTest < Minitest::Test
|
25
5
|
def setup
|
26
6
|
@server = "localhost:15672"
|
27
7
|
@queue_name = "QUEUE_NAME"
|
28
8
|
@config = Configuration.new
|
29
|
-
@client = Client.new @config
|
30
9
|
@config.logger = Logger.new("/dev/null")
|
31
|
-
@dead_lettering = DeadLettering.new(@
|
10
|
+
@dead_lettering = DeadLettering.new(@config)
|
32
11
|
end
|
33
12
|
|
34
13
|
test "raises exception when queue name wasn't specified" do
|
@@ -43,6 +22,22 @@ module Beetle
|
|
43
22
|
end
|
44
23
|
end
|
45
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
|
+
|
46
41
|
test "creates a policy by posting to the rabbitmq if dead lettering is enabled" do
|
47
42
|
stub_request(:put, "http://localhost:15672/api/policies/%2F/QUEUE_NAME_policy")
|
48
43
|
.with(basic_auth: ['guest', 'guest'])
|
@@ -56,7 +51,7 @@ module Beetle
|
|
56
51
|
}}.to_json)
|
57
52
|
.to_return(:status => 204)
|
58
53
|
|
59
|
-
@dead_lettering.set_queue_policy!(@server, @queue_name, :lazy => false, :dead_lettering => true)
|
54
|
+
@dead_lettering.set_queue_policy!(@server, @queue_name, :lazy => false, :dead_lettering => true, :routing_key => "QUEUE_NAME_dead_letter")
|
60
55
|
end
|
61
56
|
|
62
57
|
test "creates a policy by posting to the rabbitmq if lazy queues are enabled" do
|
@@ -98,7 +93,7 @@ module Beetle
|
|
98
93
|
}}.to_json)
|
99
94
|
.to_return(:status => 204)
|
100
95
|
|
101
|
-
@dead_lettering.set_queue_policy!(@server, @queue_name, :dead_lettering => true, :message_ttl => 10000)
|
96
|
+
@dead_lettering.set_queue_policy!(@server, @queue_name, :dead_lettering => true, :message_ttl => 10000, :routing_key => "QUEUE_NAME_dead_letter")
|
102
97
|
end
|
103
98
|
|
104
99
|
test "properly encodes the vhost from the configuration" do
|
@@ -116,42 +111,7 @@ module Beetle
|
|
116
111
|
|
117
112
|
@config.vhost = "foo/"
|
118
113
|
|
119
|
-
@dead_lettering.set_queue_policy!(@server, @queue_name, :dead_lettering => true)
|
120
|
-
end
|
121
|
-
end
|
122
|
-
|
123
|
-
class BindDeadLetterQueuesTest < Minitest::Test
|
124
|
-
def setup
|
125
|
-
@queue_name = "QUEUE_NAME"
|
126
|
-
@config = Configuration.new
|
127
|
-
@client = Client.new @config
|
128
|
-
@config.logger = Logger.new("/dev/null")
|
129
|
-
@dead_lettering = DeadLettering.new(@client)
|
130
|
-
@servers = ["localhost:55672"]
|
131
|
-
end
|
132
|
-
|
133
|
-
test "is does not call out to rabbit if neither dead lettering nor lazy queues are enabled" do
|
134
|
-
@client.register_queue(@queue_name, :dead_lettering => false, :lazy => false)
|
135
|
-
channel = stub('channel')
|
136
|
-
@dead_lettering.expects(:run_rabbit_http_request).never
|
137
|
-
@dead_lettering.bind_dead_letter_queues!(channel, @servers, @queue_name)
|
138
|
-
end
|
139
|
-
|
140
|
-
test "creates and connects the dead letter queue via policies when enabled" do
|
141
|
-
@client.register_queue(@queue_name, :dead_lettering => true, :lazy => false)
|
142
|
-
|
143
|
-
channel = stub('channel')
|
144
|
-
|
145
|
-
channel.expects(:queue).with("#{@queue_name}_dead_letter", {})
|
146
|
-
@dead_lettering.expects(:set_queue_policies!).with(@servers, @queue_name, :dead_lettering => true, :lazy => false)
|
147
|
-
@dead_lettering.expects(:set_queue_policies!).with(@servers, "#{@queue_name}_dead_letter",
|
148
|
-
:routing_key => @queue_name,
|
149
|
-
:message_ttl => 1000,
|
150
|
-
:dead_lettering => true,
|
151
|
-
:lazy => false
|
152
|
-
)
|
153
|
-
|
154
|
-
@dead_lettering.bind_dead_letter_queues!(channel, @servers, @queue_name)
|
114
|
+
@dead_lettering.set_queue_policy!(@server, @queue_name, :dead_lettering => true, :routing_key => "QUEUE_NAME_dead_letter")
|
155
115
|
end
|
156
116
|
end
|
157
117
|
end
|
@@ -263,7 +263,8 @@ module Beetle
|
|
263
263
|
|
264
264
|
class PublisherQueueManagementTest < Minitest::Test
|
265
265
|
def setup
|
266
|
-
@
|
266
|
+
@config = Configuration.new
|
267
|
+
@client = Client.new(@config)
|
267
268
|
@pub = Publisher.new(@client)
|
268
269
|
end
|
269
270
|
|
@@ -275,48 +276,15 @@ module Beetle
|
|
275
276
|
test "binding a queue should create it using the config and bind it to the exchange with the name specified" do
|
276
277
|
@client.register_queue("some_queue", :exchange => "some_exchange", :key => "haha.#", :arguments => {"foo" => "fighter"})
|
277
278
|
@pub.expects(:exchange).with("some_exchange").returns(:the_exchange)
|
278
|
-
|
279
|
-
q.expects(:bind).with(:the_exchange, {:key => "haha.#"})
|
280
|
-
m = mock("Bunny")
|
281
|
-
m.expects(:queue).with("some_queue", :durable => true, :passive => false, :auto_delete => false, :exclusive => false, :arguments => {"foo" => "fighter"}).returns(q)
|
282
|
-
@pub.expects(:bunny).returns(m)
|
283
|
-
|
284
|
-
@pub.send(:queue, "some_queue")
|
285
|
-
assert_equal Base::QueueInfo.new(q, false), @pub.send(:queues)["some_queue"]
|
286
|
-
end
|
287
|
-
|
288
|
-
test "binding a queue should create it using the config and bind it to the exchange with the name specified and setup policies if requested" do
|
289
|
-
@client.register_queue("some_queue", :exchange => "some_exchange", :key => "haha.#", :arguments => {"foo" => "fighter"})
|
290
|
-
@pub.expects(:exchange).with("some_exchange").returns(:the_exchange)
|
279
|
+
@pub.expects(:publish_policy_options)
|
291
280
|
q = mock("queue")
|
292
281
|
q.expects(:bind).with(:the_exchange, {:key => "haha.#"})
|
293
282
|
m = mock("Bunny")
|
294
283
|
m.expects(:queue).with("some_queue", :durable => true, :passive => false, :auto_delete => false, :exclusive => false, :arguments => {"foo" => "fighter"}).returns(q)
|
295
284
|
@pub.expects(:bunny).returns(m).twice
|
296
285
|
|
297
|
-
@pub.send(:queue, "some_queue", create_policies: true)
|
298
|
-
assert_equal Base::QueueInfo.new(q, true), @pub.send(:queues)["some_queue"]
|
299
|
-
end
|
300
|
-
|
301
|
-
test "binding a queue with create_plocies: true after having already declared it with create_plocies: false creates the policies" do
|
302
|
-
@client.register_queue("some_queue", :exchange => "some_exchange", :key => "haha.#", :arguments => {"foo" => "fighter"})
|
303
|
-
@pub.expects(:exchange).with("some_exchange").returns(:the_exchange)
|
304
|
-
q = mock("queue")
|
305
|
-
q.expects(:bind).with(:the_exchange, {:key => "haha.#"})
|
306
|
-
m = mock("Bunny")
|
307
|
-
m.expects(:queue).with("some_queue", :durable => true, :passive => false, :auto_delete => false, :exclusive => false, :arguments => {"foo" => "fighter"}).returns(q)
|
308
|
-
@pub.expects(:bunny).returns(m)
|
309
|
-
|
310
286
|
@pub.send(:queue, "some_queue")
|
311
|
-
assert_equal
|
312
|
-
|
313
|
-
@pub.expects(:exchange).with("some_exchange").returns(:the_exchange)
|
314
|
-
q.expects(:bind).with(:the_exchange, {:key => "haha.#"})
|
315
|
-
m.expects(:queue).with("some_queue", :durable => true, :passive => false, :auto_delete => false, :exclusive => false, :arguments => {"foo" => "fighter"}).returns(q)
|
316
|
-
@pub.expects(:bunny).returns(m).twice
|
317
|
-
|
318
|
-
@pub.send(:queue, "some_queue", create_policies: true)
|
319
|
-
assert_equal Base::QueueInfo.new(q, true), @pub.send(:queues)["some_queue"]
|
287
|
+
assert_equal q, @pub.send(:queues)["some_queue"]
|
320
288
|
end
|
321
289
|
|
322
290
|
test "should bind the defined queues for the used exchanges when publishing" do
|
@@ -89,7 +89,7 @@ module Beetle
|
|
89
89
|
q = mock("queue a")
|
90
90
|
q.expects(:subscribed?).returns(true)
|
91
91
|
q.expects(:unsubscribe)
|
92
|
-
@sub.stubs(:queues).returns(
|
92
|
+
@sub.stubs(:queues).returns("a" => q)
|
93
93
|
@sub.__send__(:pause, "a")
|
94
94
|
end
|
95
95
|
|
@@ -97,7 +97,7 @@ module Beetle
|
|
97
97
|
q = mock("queue a")
|
98
98
|
q.expects(:subscribed?).returns(false)
|
99
99
|
q.expects(:unsubscribe).never
|
100
|
-
@sub.stubs(:queues).returns(
|
100
|
+
@sub.stubs(:queues).returns("a" => q)
|
101
101
|
@sub.__send__(:pause, "a")
|
102
102
|
end
|
103
103
|
|
@@ -105,7 +105,7 @@ module Beetle
|
|
105
105
|
q = mock("queue a")
|
106
106
|
q.expects(:subscribed?).returns(false)
|
107
107
|
q.expects(:subscribe)
|
108
|
-
@sub.stubs(:queues).returns(
|
108
|
+
@sub.stubs(:queues).returns("a" => q)
|
109
109
|
@sub.__send__(:resume, "a")
|
110
110
|
end
|
111
111
|
|
@@ -113,7 +113,7 @@ module Beetle
|
|
113
113
|
q = mock("queue a")
|
114
114
|
q.expects(:subscribed?).returns(true)
|
115
115
|
q.expects(:subscribe).never
|
116
|
-
@sub.stubs(:queues).returns(
|
116
|
+
@sub.stubs(:queues).returns("a" => q)
|
117
117
|
@sub.__send__(:resume, "a")
|
118
118
|
end
|
119
119
|
|
@@ -146,27 +146,17 @@ module Beetle
|
|
146
146
|
test "binding a queue should create it using the config and bind it to the exchange with the name specified" do
|
147
147
|
@client.register_queue("some_queue", "durable" => true, "exchange" => "some_exchange", "key" => "haha.#", "arguments" => {"schmu" => 5})
|
148
148
|
@sub.expects(:exchange).with("some_exchange").returns(:the_exchange)
|
149
|
+
@sub.expects(:publish_policy_options)
|
149
150
|
q = mock("queue")
|
150
151
|
q.expects(:bind).with(:the_exchange, {:key => "haha.#"})
|
151
|
-
|
152
|
-
|
153
|
-
|
152
|
+
channel = mock("MQ")
|
153
|
+
creation_opts = {:durable => true, :passive => false, :auto_delete => false, :exclusive => false, :arguments => {"schmu" => 5}}
|
154
|
+
channel.expects(:queue).with("some_queue", creation_opts).returns(q)
|
155
|
+
@sub.expects(:channel).returns(channel).twice
|
156
|
+
@sub.expects(:bind_dead_letter_queue!).with(channel, "some_queue", creation_opts)
|
154
157
|
|
155
158
|
@sub.send(:queue, "some_queue")
|
156
|
-
assert_equal q, @sub.send(:queues)["some_queue"]
|
157
|
-
end
|
158
|
-
|
159
|
-
test "binding a queue should create it using the config and bind it to the exchange with the name specified and create policies if requested" do
|
160
|
-
@client.register_queue("some_queue", "durable" => true, "exchange" => "some_exchange", "key" => "haha.#", "arguments" => {"schmu" => 5})
|
161
|
-
@sub.expects(:exchange).with("some_exchange").returns(:the_exchange)
|
162
|
-
q = mock("queue")
|
163
|
-
q.expects(:bind).with(:the_exchange, {:key => "haha.#"})
|
164
|
-
m = mock("MQ")
|
165
|
-
m.expects(:queue).with("some_queue", :durable => true, :passive => false, :auto_delete => false, :exclusive => false, :arguments => {"schmu" => 5}).returns(q)
|
166
|
-
@sub.expects(:channel).returns(m).twice
|
167
|
-
|
168
|
-
@sub.send(:queue, "some_queue", create_policies: true)
|
169
|
-
assert_equal q, @sub.send(:queues)["some_queue"].queue
|
159
|
+
assert_equal q, @sub.send(:queues)["some_queue"]
|
170
160
|
end
|
171
161
|
|
172
162
|
test "binding queues should bind all queues" do
|
@@ -370,7 +360,7 @@ module Beetle
|
|
370
360
|
q = mock("QUEUE")
|
371
361
|
subscription_options = {:ack => true, :key => "#"}
|
372
362
|
q.expects(:subscribe).with(subscription_options).yields(header, "foo")
|
373
|
-
@sub.expects(:queues).returns(
|
363
|
+
@sub.expects(:queues).returns("some_queue" => q).once
|
374
364
|
@sub.send(:subscribe, "some_queue")
|
375
365
|
assert block_called
|
376
366
|
assert @sub.__send__(:has_subscription?, "some_queue")
|
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.rc2
|
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-
|
15
|
+
date: 2019-05-13 00:00:00.000000000 Z
|
16
16
|
dependencies:
|
17
17
|
- !ruby/object:Gem::Dependency
|
18
18
|
name: bunny
|