beetle 3.0.0.rc1 → 3.0.0.rc2

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 299657b394d85d53b70417554db9a3ca53de5339dc0fc777e1555536237ccf1b
4
- data.tar.gz: a4fda19185d645fbb26e563b7b7c72ffe67d03ef3cc621a581b7b1cee38b3178
3
+ metadata.gz: fb0489f8580ec11b65b79718c9e76c0f4b26a14af2fbbf471cf4b630fca5fa7d
4
+ data.tar.gz: 0f3ef313bfaf103eecfd1c1714c5d28b6ec10bc7ce0313e55f0cee6e00f2086a
5
5
  SHA512:
6
- metadata.gz: 3b6c98dd094e445db0424aab1c992eb9245df6fb4e402c45d087c8ca395c9bfd2f3ec57d95999a79ce5f4853d1c02e139a829b962f6cef896c73004a299743ad
7
- data.tar.gz: 1324bd1753c97574cf0dd657f7096be41e26d76f271525c124aa198286056cbd8673bf5ff0894bc761b94351cdd14d1dbd3504e3925fcc6e11804f6ae99b19dd
6
+ metadata.gz: 51aa8c7058c8149daa6c2d69c1ae8a26731957290f06e4bde26a06613e260030f9cb16d286415958db74afcb38bdc74a9ccacc58643ceb25227662a800fada22
7
+ data.tar.gz: ae1eed22b04f81c612aff1ad88836e57df2db997a923da8f1819d8675093a9533f377e6429928049f9665b5a7548cdbbfb48172ddfbb361bac2e2adbcfba507b
@@ -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 HTPP calls to set up queue policies can in fact crash a server.
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}"
@@ -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
- QueueInfo = Struct.new(:queue, :create_policies)
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, create_policies: create_policies)
70
+ the_queue = bind_queue!(queue_name, creation_options, exchange_name, binding_options)
76
71
  end
77
- info = QueueInfo.new(the_queue, create_policies)
72
+ the_queue
78
73
  end
79
- info.queue
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
@@ -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)
@@ -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 :client, :config
8
+ attr_reader :config
9
9
 
10
- def initialize(client)
11
- @client = client
12
- @config = client.config
10
+ def initialize(config)
11
+ @config = config
13
12
  end
14
13
 
15
- def bind_dead_letter_queues!(channel, servers, target_queue, creation_keys = {})
16
- policy_options = client.queues[target_queue].slice(:dead_lettering, :lazy)
17
- if policy_options[:dead_lettering]
18
- dead_letter_queue_name = dead_letter_queue_name(target_queue)
19
- logger.info("Beetle: creating dead letter queue #{dead_letter_queue_name} with opts: #{creation_keys.inspect}")
20
- channel.queue(dead_letter_queue_name, creation_keys)
21
- end
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
- if policy_options[:dead_lettering]
24
- logger.info("Beetle: setting #{dead_letter_queue_name} as dead letter queue of #{target_queue} on all servers")
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
- def set_queue_policies!(servers, queue_name, options={})
41
- servers.each { |server| set_queue_policy!(server, queue_name, options) }
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"] = dead_letter_routing_key(queue_name, options)
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.start(uri.hostname, config.api_port, :read_timeout => config.dead_lettering_read_timeout) do |http|
95
- block.call(http) if block_given?
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
@@ -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, create_policies: false)
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
 
@@ -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].queue.subscribe(keys, &callback)
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].queue.subscribed?
153
- queues[queue_name].queue.unsubscribe
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].queue.subscribed?
157
+ return if queues[queue_name].subscribed?
158
158
  keys, callback = subscriptions[queue_name]
159
- queues[queue_name].queue.subscribe(keys, &callback)
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, create_policies: false)
207
+ def bind_queue!(queue_name, creation_keys, exchange_name, binding_keys)
208
208
  queue = channel.queue(queue_name, creation_keys)
209
- target_servers = @client.servers + @client.additional_subscription_servers
210
- if create_policies
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
@@ -1,3 +1,3 @@
1
1
  module Beetle
2
- VERSION = "3.0.0.rc1"
2
+ VERSION = "3.0.0.rc2"
3
3
  end
@@ -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
@@ -15,20 +15,20 @@ module Beetle
15
15
  assert_equal [], @client.additional_subscription_servers
16
16
  end
17
17
 
18
- test "should have no exchanges" do
19
- assert @client.exchanges.empty?
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 no queues" do
23
- assert @client.queues.empty?
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
- assert @client.messages.empty?
27
+ assert_equal [], @client.messages.keys
28
28
  end
29
29
 
30
- test "should have no bindings" do
31
- assert @client.bindings.empty?
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(@client)
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
- @client = Client.new
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
- q = mock("queue")
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 Base::QueueInfo.new(q, false), @pub.send(:queues)["some_queue"]
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({"a" => Base::QueueInfo.new(q,false)})
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({"a" => Base::QueueInfo.new(q,false)})
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({"a" => Base::QueueInfo.new(q,false)})
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({"a" => Base::QueueInfo.new(q,false)})
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
- m = mock("MQ")
152
- m.expects(:queue).with("some_queue", :durable => true, :passive => false, :auto_delete => false, :exclusive => false, :arguments => {"schmu" => 5}).returns(q)
153
- @sub.expects(:channel).returns(m)
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"].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({"some_queue" => Base::QueueInfo.new(q,false)}).once
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.rc1
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-04-26 00:00:00.000000000 Z
15
+ date: 2019-05-13 00:00:00.000000000 Z
16
16
  dependencies:
17
17
  - !ruby/object:Gem::Dependency
18
18
  name: bunny