bmabey-rosetta_queue 0.2.0 → 0.3.3

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.
Files changed (59) hide show
  1. data/History.txt +6 -3
  2. data/README.rdoc +1 -193
  3. data/Rakefile +7 -1
  4. data/cucumber.yml +1 -1
  5. data/examples/sample_amqp_consumer.rb +13 -3
  6. data/examples/sample_amqp_fanout_consumer.rb +6 -3
  7. data/examples/sample_amqp_fanout_producer.rb +3 -2
  8. data/examples/sample_amqp_producer.rb +2 -1
  9. data/features/filtering.feature +13 -13
  10. data/features/messaging.feature +28 -20
  11. data/features/step_definitions/common_messaging_steps.rb +54 -17
  12. data/features/step_definitions/filtering_steps.rb +2 -2
  13. data/features/step_definitions/point_to_point_steps.rb +19 -9
  14. data/features/step_definitions/publish_subscribe_steps.rb +22 -8
  15. data/features/support/env.rb +2 -0
  16. data/features/support/sample_consumers.rb +6 -6
  17. data/lib/rosetta_queue.rb +1 -0
  18. data/lib/rosetta_queue/adapter.rb +6 -6
  19. data/lib/rosetta_queue/adapters/amqp.rb +6 -3
  20. data/lib/rosetta_queue/adapters/amqp_evented.rb +22 -22
  21. data/lib/rosetta_queue/adapters/amqp_synch.rb +42 -36
  22. data/lib/rosetta_queue/adapters/base.rb +3 -3
  23. data/lib/rosetta_queue/adapters/beanstalk.rb +5 -5
  24. data/lib/rosetta_queue/adapters/fake.rb +5 -5
  25. data/lib/rosetta_queue/adapters/null.rb +9 -9
  26. data/lib/rosetta_queue/adapters/stomp.rb +25 -12
  27. data/lib/rosetta_queue/base.rb +2 -2
  28. data/lib/rosetta_queue/consumer.rb +4 -4
  29. data/lib/rosetta_queue/consumer_managers/base.rb +8 -6
  30. data/lib/rosetta_queue/consumer_managers/evented.rb +5 -5
  31. data/lib/rosetta_queue/consumer_managers/threaded.rb +4 -4
  32. data/lib/rosetta_queue/core_ext/string.rb +3 -3
  33. data/lib/rosetta_queue/core_ext/time.rb +20 -0
  34. data/lib/rosetta_queue/destinations.rb +6 -6
  35. data/lib/rosetta_queue/filters.rb +8 -8
  36. data/lib/rosetta_queue/logger.rb +2 -2
  37. data/lib/rosetta_queue/message_handler.rb +10 -4
  38. data/lib/rosetta_queue/producer.rb +2 -2
  39. data/lib/rosetta_queue/spec_helpers/hash.rb +3 -3
  40. data/lib/rosetta_queue/spec_helpers/helpers.rb +8 -8
  41. data/lib/rosetta_queue/spec_helpers/publishing_matchers.rb +26 -26
  42. data/spec/rosetta_queue/adapter_spec.rb +27 -27
  43. data/spec/rosetta_queue/adapters/amqp_synchronous_spec.rb +21 -1
  44. data/spec/rosetta_queue/adapters/beanstalk_spec.rb +3 -3
  45. data/spec/rosetta_queue/adapters/fake_spec.rb +6 -6
  46. data/spec/rosetta_queue/adapters/null_spec.rb +5 -5
  47. data/spec/rosetta_queue/adapters/shared_adapter_behavior.rb +4 -4
  48. data/spec/rosetta_queue/adapters/shared_fanout_behavior.rb +1 -1
  49. data/spec/rosetta_queue/adapters/stomp_spec.rb +39 -18
  50. data/spec/rosetta_queue/consumer_managers/evented_spec.rb +6 -6
  51. data/spec/rosetta_queue/consumer_managers/shared_manager_behavior.rb +3 -3
  52. data/spec/rosetta_queue/consumer_managers/threaded_spec.rb +5 -5
  53. data/spec/rosetta_queue/consumer_spec.rb +13 -13
  54. data/spec/rosetta_queue/core_ext/string_spec.rb +3 -3
  55. data/spec/rosetta_queue/destinations_spec.rb +8 -8
  56. data/spec/rosetta_queue/filters_spec.rb +16 -16
  57. data/spec/rosetta_queue/producer_spec.rb +15 -15
  58. data/spec/rosetta_queue/shared_messaging_behavior.rb +6 -6
  59. metadata +3 -2
@@ -2,7 +2,7 @@ module RosettaQueue
2
2
  module Gateway
3
3
 
4
4
  class BaseAdapter
5
-
5
+
6
6
  protected
7
7
 
8
8
  def options_for(message_handler)
@@ -13,7 +13,7 @@ module RosettaQueue
13
13
  raise DestinationNotFound.new("Missing destination!") unless message_handler.destination
14
14
  @dest ||= Destinations.lookup(message_handler.destination.to_sym)
15
15
  end
16
-
16
+
17
17
  def filter_receiving(msg)
18
18
  Filters.process_receiving(msg)
19
19
  end
@@ -21,7 +21,7 @@ module RosettaQueue
21
21
  def filter_sending(msg)
22
22
  Filters.process_sending(msg)
23
23
  end
24
-
24
+
25
25
  end
26
26
  end
27
27
  end
@@ -2,7 +2,7 @@ require 'beanstalk-client'
2
2
 
3
3
  module RosettaQueue
4
4
  module Gateway
5
-
5
+
6
6
  class BeanstalkAdapter < BaseAdapter
7
7
 
8
8
  def ack(msg)
@@ -22,7 +22,7 @@ module RosettaQueue
22
22
  msg.delete
23
23
  msg
24
24
  end
25
-
25
+
26
26
  def receive_once(destination=nil, opts={})
27
27
  receive.body
28
28
  end
@@ -39,14 +39,14 @@ module RosettaQueue
39
39
  message_handler.on_message(filter_receiving(msg))
40
40
  end
41
41
  end
42
-
42
+
43
43
  def send_message(destination, message, options)
44
- RosettaQueue.logger.info("Publishing to #{destination} :: #{message}")
44
+ RosettaQueue.logger.info("Publishing to #{destination} :: #{message}")
45
45
  @conn.put(message)
46
46
  end
47
47
 
48
48
  private
49
-
49
+
50
50
  def running(&block)
51
51
  loop(&block)
52
52
  end
@@ -1,6 +1,6 @@
1
1
  module RosettaQueue
2
2
  module Gateway
3
-
3
+
4
4
  class FakeAdapter
5
5
 
6
6
  def initialize
@@ -10,17 +10,17 @@ module RosettaQueue
10
10
  def send_message(queue, message, headers)
11
11
  @messages << {'queue' => queue, 'message' => RosettaQueue::Filters::process_receiving(message), 'headers' => headers}
12
12
  end
13
-
13
+
14
14
  def messages_sent_to(queue)
15
15
  (queue ? @messages.select{|message| message['queue'] == queue} : @messages).map{|m| m['message']}
16
16
  end
17
-
17
+
18
18
  def queues
19
19
  @messages.map {|message| message['queue']}
20
20
  end
21
21
 
22
22
  end
23
-
23
+
24
24
  end
25
-
25
+
26
26
  end
@@ -1,8 +1,8 @@
1
1
  module RosettaQueue
2
2
  module Gateway
3
-
3
+
4
4
  # The null adapter lets all send messages enter into the ether and so is ideal for modes
5
- # when you do not want to incur the overhead of a real adapter. You can not consume with
5
+ # when you do not want to incur the overhead of a real adapter. You can not consume with
6
6
  # this adapter however.
7
7
  #
8
8
  # In your RosettaQueue definition block, and your using rails, you could base your adapter type on Rails.env:
@@ -18,11 +18,11 @@ module RosettaQueue
18
18
  # a.type = "null"
19
19
  # end
20
20
  # end
21
- #
22
- # (if you follow this example and are using stories be sure
21
+ #
22
+ # (if you follow this example and are using stories be sure
23
23
  # to set ENV["RUNNING_STORIES"] = "true" in your helper.rb or env.rb file)
24
24
  class NullAdapter
25
-
25
+
26
26
  def initialize(adapter_settings)
27
27
  # no-op
28
28
  end
@@ -30,15 +30,15 @@ module RosettaQueue
30
30
  def disconnect
31
31
  # no-op
32
32
  end
33
-
33
+
34
34
  def receive
35
35
  raise "Null Adpater is in use, you can not consume messages!"
36
36
  end
37
-
37
+
38
38
  def receive_with(message_handler)
39
39
  raise "Null Adpater is in use, you can not consume messages!"
40
40
  end
41
-
41
+
42
42
  def send_message(queue, message, options)
43
43
  # no-op
44
44
  end
@@ -46,7 +46,7 @@ module RosettaQueue
46
46
  def subscribe(queue, options)
47
47
  # no-op
48
48
  end
49
-
49
+
50
50
  def unsubscribe(queue)
51
51
  # no-op
52
52
  end
@@ -2,19 +2,20 @@ require 'stomp'
2
2
 
3
3
  module RosettaQueue
4
4
  module Gateway
5
-
5
+
6
6
  class StompAdapter < BaseAdapter
7
7
 
8
8
  def ack(msg)
9
+ raise AdapterException, "Unable to ack client because message-id is blank. Are your message handler options correct? (i.e., :ack => 'client')" if msg.headers["message-id"].nil?
9
10
  @conn.ack(msg.headers["message-id"])
10
11
  end
11
12
 
12
13
  def initialize(adapter_settings = {})
13
- raise "Missing adapter settings" if adapter_settings.empty?
14
- @conn = Stomp::Connection.open(adapter_settings[:user],
15
- adapter_settings[:password],
16
- adapter_settings[:host],
17
- adapter_settings[:port],
14
+ raise AdapterException, "Missing adapter settings" if adapter_settings.empty?
15
+ @conn = Stomp::Connection.open(adapter_settings[:user],
16
+ adapter_settings[:password],
17
+ adapter_settings[:host],
18
+ adapter_settings[:port],
18
19
  true)
19
20
  end
20
21
 
@@ -28,7 +29,7 @@ module RosettaQueue
28
29
  ack(msg) unless options[:ack].nil?
29
30
  msg
30
31
  end
31
-
32
+
32
33
  def receive_once(destination, opts)
33
34
  subscribe(destination, opts)
34
35
  msg = receive(opts).body
@@ -50,26 +51,38 @@ module RosettaQueue
50
51
  Thread.current[:processing] = false
51
52
  end
52
53
  end
53
-
54
+
54
55
  def send_message(destination, message, options)
55
- RosettaQueue.logger.info("Publishing to #{destination} :: #{message}")
56
+ RosettaQueue.logger.info("Publishing to #{destination} :: #{message}")
56
57
  @conn.send(destination, message, options)
57
58
  end
58
59
 
59
60
  def subscribe(destination, options)
60
61
  @conn.subscribe(destination, options)
61
62
  end
62
-
63
+
63
64
  def unsubscribe(destination)
64
65
  @conn.unsubscribe(destination)
65
66
  end
66
-
67
+
67
68
  private
68
-
69
+
69
70
  def running(&block)
70
71
  loop(&block)
71
72
  end
72
73
 
73
74
  end
75
+
76
+ class StompAdapterProxy
77
+
78
+ def initialize(adapter, msg)
79
+ @adapter, @msg = adapter, msg
80
+ end
81
+
82
+ def ack
83
+ @adapter.ack(@msg)
84
+ end
85
+ end
86
+
74
87
  end
75
88
  end
@@ -1,5 +1,5 @@
1
1
  module RosettaQueue
2
-
2
+
3
3
  class Base
4
4
 
5
5
  def disconnect
@@ -12,4 +12,4 @@ module RosettaQueue
12
12
  end
13
13
 
14
14
  end
15
- end
15
+ end
@@ -3,17 +3,17 @@ module RosettaQueue
3
3
 
4
4
  def self.receive(destination, options = {})
5
5
  RosettaQueue::Adapter.instance.receive_once(Destinations.lookup(destination), options)
6
-
6
+
7
7
  rescue Exception=>e
8
8
  RosettaQueue.logger.error("Caught exception in Consumer.receive: #{$!}\n" + e.backtrace.join("\n\t"))
9
9
  end
10
10
 
11
11
  def self.delete(destination, options={})
12
12
  RosettaQueue::Adapter.instance.delete(Destinations.lookup(destination), options)
13
-
13
+
14
14
  rescue Exception=>e
15
15
  RosettaQueue.logger.error("Caught exception in Consumer.delete: #{$!}\n" + e.backtrace.join("\n\t"))
16
- end
16
+ end
17
17
 
18
18
  def initialize(message_handler)
19
19
  @message_handler = message_handler
@@ -21,7 +21,7 @@ module RosettaQueue
21
21
 
22
22
  def receive
23
23
  connection.receive_with(@message_handler)
24
-
24
+
25
25
  rescue Exception=>e
26
26
  RosettaQueue.logger.error("Caught exception in Consumer#receive: #{$!}\n" + e.backtrace.join("\n\t"))
27
27
  end
@@ -1,22 +1,24 @@
1
1
  module RosettaQueue
2
-
2
+
3
3
  class BaseManager
4
4
  attr_reader :consumers
5
5
 
6
6
  class << self
7
7
  def create
8
- yield self.new
8
+ manager = self.new
9
+ yield manager
10
+ manager
9
11
  end
10
12
  end
11
-
13
+
12
14
  def initialize
13
15
  @consumers = {}
14
16
  end
15
-
17
+
16
18
  def add(message_handler)
17
19
  key = message_handler.class.to_s.underscore.to_sym
18
20
  @consumers[key] = Consumer.new(message_handler)
19
21
  end
20
-
21
- end
22
+
23
+ end
22
24
  end
@@ -2,9 +2,9 @@ require 'rosetta_queue/consumer_managers/base'
2
2
  require 'mq'
3
3
 
4
4
  module RosettaQueue
5
-
5
+
6
6
  class EventedManager < BaseManager
7
-
7
+
8
8
  def start
9
9
  EM.run {
10
10
  trap_interruptions
@@ -19,20 +19,20 @@ module RosettaQueue
19
19
  end
20
20
  }
21
21
  end
22
-
22
+
23
23
  def stop
24
24
  RosettaQueue.logger.info("Shutting down event machine...")
25
25
  EM.stop
26
26
  end
27
27
 
28
28
  private
29
-
29
+
30
30
  def trap_interruptions
31
31
  trap("INT") {
32
32
  RosettaQueue.logger.warn("Interrupt received. Shutting down...")
33
33
  EM.stop
34
34
  }
35
-
35
+
36
36
  trap("TERM") {
37
37
  RosettaQueue.logger.warn("Interrupt received. Shutting down...")
38
38
  EM.stop
@@ -25,10 +25,10 @@ module RosettaQueue
25
25
  def join_threads
26
26
  @threads.each { |thread| thread.join }
27
27
  end
28
-
28
+
29
29
  def shutdown_requested
30
30
  RosettaQueue.logger.error "Shutdown requested, starting to prune threads..."
31
-
31
+
32
32
  while @threads.any? { |n, t| t.alive? }
33
33
  RosettaQueue.logger.info "Calling stop_threads"
34
34
  stop_threads
@@ -73,7 +73,7 @@ module RosettaQueue
73
73
  Thread.pass
74
74
  end
75
75
  end
76
- end
76
+ end
77
77
  end
78
78
 
79
79
  def stop_threads
@@ -86,8 +86,8 @@ module RosettaQueue
86
86
  next
87
87
  end
88
88
  RosettaQueue.logger.debug("#{key} Stopping thread #{thread} and disconnecting the consumer")
89
- @consumers[key].disconnect
90
89
  thread.kill
90
+ @consumers[key].disconnect
91
91
  end
92
92
  end
93
93
  end
@@ -7,11 +7,11 @@ class String
7
7
  self.first.downcase + camelize(self)[1..-1]
8
8
  end
9
9
  end
10
-
10
+
11
11
  def classify
12
12
  camelize(self.sub(/.*\./, ''))
13
13
  end
14
-
14
+
15
15
  def underscore
16
16
  self.gsub(/::/, '/').
17
17
  gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
@@ -19,4 +19,4 @@ class String
19
19
  tr("-", "_").
20
20
  downcase
21
21
  end
22
- end
22
+ end
@@ -0,0 +1,20 @@
1
+ require 'time'
2
+
3
+ class Time
4
+
5
+ DATE_FORMATS = {
6
+ :db => "%Y-%m-%d %H:%M:%S",
7
+ :number => "%Y%m%d%H%M%S",
8
+ :time => "%H:%M",
9
+ :short => "%d %b %H:%M",
10
+ :long => "%B %d, %Y %H:%M",
11
+ :long_ordinal => lambda { |time| time.strftime("%B #{time.day.ordinalize}, %Y %H:%M") },
12
+ :rfc822 => lambda { |time| time.strftime("%a, %d %b %Y %H:%M:%S #{time.formatted_offset(false)}") }
13
+ }
14
+
15
+ def to_formatted_s(format = :default)
16
+ return to_default_s unless formatter = DATE_FORMATS[format]
17
+ formatter.respond_to?(:call) ? formatter.call(self).to_s : strftime(formatter)
18
+ end
19
+
20
+ end
@@ -1,7 +1,7 @@
1
1
  module RosettaQueue
2
2
 
3
3
  class Destinations
4
-
4
+
5
5
  @dest = {}
6
6
 
7
7
  class << self
@@ -10,25 +10,25 @@ module RosettaQueue
10
10
  def define
11
11
  yield self
12
12
  end
13
-
13
+
14
14
  def clear
15
15
  @dest.clear
16
16
  end
17
-
17
+
18
18
  def lookup(dest_name)
19
19
  mapping = dest[dest_name.to_sym]
20
20
  raise "No destination mapping for '#{dest_name}' has been defined!" unless mapping
21
21
  return mapping
22
22
  end
23
-
23
+
24
24
  def map(key, dest)
25
25
  @dest[key] = dest
26
26
  end
27
-
27
+
28
28
  def queue_names
29
29
  @dest.values
30
30
  end
31
31
  end
32
32
 
33
33
  end
34
- end
34
+ end