message_queue 0.0.4 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (38) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +87 -2
  3. data/examples/{publisher.rb → producer.rb} +4 -3
  4. data/examples/producible_consumable.rb +28 -0
  5. data/lib/message_queue/adapter.rb +4 -0
  6. data/lib/message_queue/adapters/bunny/connection.rb +26 -28
  7. data/lib/message_queue/adapters/bunny/consumer.rb +21 -11
  8. data/lib/message_queue/adapters/bunny/{publisher.rb → producer.rb} +12 -12
  9. data/lib/message_queue/adapters/memory/connection.rb +12 -0
  10. data/lib/message_queue/adapters/memory/consumer.rb +34 -0
  11. data/lib/message_queue/adapters/memory/producer.rb +11 -0
  12. data/lib/message_queue/adapters/memory.rb +11 -0
  13. data/lib/message_queue/connection.rb +64 -0
  14. data/lib/message_queue/consumable.rb +83 -0
  15. data/lib/message_queue/consumable_runner.rb +28 -0
  16. data/lib/message_queue/consumer.rb +18 -0
  17. data/lib/message_queue/error_handlers/airbrake.rb +19 -0
  18. data/lib/message_queue/error_handlers/logger.rb +16 -0
  19. data/lib/message_queue/logging.rb +30 -0
  20. data/lib/message_queue/message.rb +14 -0
  21. data/lib/message_queue/options_helper.rb +26 -0
  22. data/lib/message_queue/producer.rb +29 -0
  23. data/lib/message_queue/producible.rb +49 -0
  24. data/lib/message_queue/rails.rb +19 -0
  25. data/lib/message_queue/serializer.rb +4 -0
  26. data/lib/message_queue/serializers/json.rb +4 -0
  27. data/lib/message_queue/serializers/message_pack.rb +4 -0
  28. data/lib/message_queue/serializers/plain.rb +4 -0
  29. data/lib/message_queue/version.rb +1 -1
  30. data/lib/message_queue.rb +118 -1
  31. data/test/adapters/bunny_test.rb +47 -32
  32. data/test/adapters/memory_test.rb +26 -0
  33. data/test/consumable_test.rb +45 -0
  34. data/test/message_queue_test.rb +22 -0
  35. data/test/options_helper_test.rb +23 -0
  36. data/test/producible_test.rb +41 -0
  37. data/test/support/message_queue.yml +1 -0
  38. metadata +29 -4
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 69c5d3a42305c245b66001e3f1eb926db2e79d79
4
- data.tar.gz: 67afed64dc220d8d9853dc608c5affc0c6e5fb1e
3
+ metadata.gz: 6e91039cfe1a4655089a9d9fe51b6f5f40ac0040
4
+ data.tar.gz: 399c152cae5cb9af53a1831bf6f7e9b86c0ff3f9
5
5
  SHA512:
6
- metadata.gz: 17ad92ad1ca7187ec5ad36da7c1ce51e8b835b6e4d85693ab26f6cc0cea6af3b0de60f6dace19c2c30a5cac5dfaed8d8130278a6eb8831414d45ee569420001d
7
- data.tar.gz: 2b6ba6e40c26fd2be1939b0593f911ba942fd640cd3a763c11c5606756cc53ea2996de3d7c7e68baaa5757a661ba8156e59953f92332e06025765a2cc5fa6e85
6
+ metadata.gz: 41fd54adc323d25ee56b597da2c8b25b8cd72177af4fae1d9f79b31412e953caf1c5d738c0f767fe684cd758bc6902f93d8f8f30fd7da1849c05dadf19d71f13
7
+ data.tar.gz: 62e935dde186e86ee8c0df12ae81d8e82b7e40e0ae0a35323d9f040c99f827291d054bff14f74c3da425f4f0f402d3c80643a90ed55d83e260bde7642f30ca56
data/README.md CHANGED
@@ -18,9 +18,15 @@ Or install it yourself as:
18
18
 
19
19
  ## Usage
20
20
 
21
+ ### with_connection
22
+
23
+ `with_connection` initializes a connection using the specified adapter
24
+ and serializer, connects to the message queue, runs a block of code and
25
+ disconnects.
26
+
21
27
  ```ruby
22
28
  MessageQueue.with_connection(:adapter => :bunny, :serializer => :message_pack) do |conn|
23
- publisher = conn.new_publisher(
29
+ producer = conn.new_producer(
24
30
  :exchange => {
25
31
  :name => "time",
26
32
  :type => :topic
@@ -44,16 +50,95 @@ MessageQueue.with_connection(:adapter => :bunny, :serializer => :message_pack) d
44
50
  puts "Received message: #{payload}"
45
51
  end
46
52
 
47
- publisher.publish Time.now.to_s
53
+ producer.publish Time.now.to_s
48
54
 
49
55
  sleep 1
50
56
  end
51
57
  ```
52
58
 
59
+ You could maintain a global connection by using the `connect` method on
60
+ `MessageQueue`.
61
+
62
+ ```ruby
63
+ MessageQueue.connect(:adater => :bunny, :serializer => :json)
64
+ puts MessageQueue.connected? # => true
65
+
66
+ producer = MessageQueue.new_producer(
67
+ :exchange => {
68
+ :name => "time",
69
+ :type => :topic
70
+ },
71
+ :message => {
72
+ :routing_key => "time.now"
73
+ }
74
+ )
75
+
76
+ consumer = MessageQueue.new_consumer(
77
+ :queue => {
78
+ :name => "print_time_now"
79
+ },
80
+ :exchange => {
81
+ :name => "time",
82
+ :routing_key => "time.#"
83
+ }
84
+ )
85
+
86
+ consumer.subscribe do |delivery_info, metadata, payload|
87
+ puts "Received message: #{payload}"
88
+ end
89
+
90
+ producer.publish Time.now.to_s
91
+
92
+ sleep 1
93
+
94
+ MessageQueue.disconnect
95
+ puts MessageQueue.connected? # => false
96
+ ```
97
+
98
+ You could also mix in the `MessageQueue::Producible` module and the
99
+ `MessageQueue::Consumable` module to your producer class and consumer
100
+ class respectively. The consumer class needs to implement a `process`
101
+ method which will be passed a `MessageQueue::Message` instance when it
102
+ receives a message.
103
+
104
+ ```ruby
105
+ class Producer
106
+ include MessageQueue::Producible
107
+
108
+ exchange :name => "time", :type => :topic
109
+ message :routing_key => "time.now", :mandatory => true
110
+ end
111
+
112
+ class Consumer
113
+ include MessageQueue::Consumable
114
+
115
+ queue :name => "print_time_now"
116
+ exchange :name => "time", :routing_key => "time.#"
117
+
118
+ def process(message)
119
+ puts "Received message #{message.payload}"
120
+ end
121
+ end
122
+
123
+ MessageQueue.connect(:adater => :bunny, :serializer => :json)
124
+ Producer.new.publish(Time.now.to_s)
125
+
126
+ sleep 1
127
+
128
+ MessageQueue.disconnect
129
+ ```
130
+
53
131
  ## Examples
54
132
 
55
133
  See [examples](https://github.com/jingweno/message_queue/tree/master/examples).
56
134
 
135
+ ## Rails
136
+
137
+ For Rails, `message_queue` automatically loads settings from
138
+ `RAILS_ROOT/config/message_queue.yml`. If the file doesn't exist, it
139
+ initializes the queue in
140
+ [memory](https://github.com/jingweno/message_queue/tree/master/lib/message_queue/adapters/memory) mode.
141
+
57
142
  ## Contributing
58
143
 
59
144
  1. Fork it
@@ -1,15 +1,16 @@
1
1
  require_relative "../lib/message_queue"
2
2
 
3
3
  MessageQueue.with_connection(:adapter => :bunny, :serializer => :message_pack) do |conn|
4
- publisher = conn.new_publisher(
4
+ producer = conn.new_producer(
5
5
  :exchange => {
6
6
  :name => "time",
7
7
  :type => :topic
8
8
  },
9
9
  :message => {
10
- :routing_key => "time.now"
10
+ :routing_key => "time.now",
11
+ :mandatory => true
11
12
  }
12
13
  )
13
14
 
14
- publisher.publish Time.now.to_s
15
+ producer.publish Time.now.to_s
15
16
  end
@@ -0,0 +1,28 @@
1
+ require_relative "../lib/message_queue"
2
+
3
+ class Producer
4
+ include MessageQueue::Producible
5
+
6
+ exchange :name => "time", :type => :topic
7
+ message :routing_key => "time.now", :mandatory => true
8
+ end
9
+
10
+ class Consumer
11
+ include MessageQueue::Consumable
12
+
13
+ queue :name => "print_time_now"
14
+ exchange :name => "time", :routing_key => "time.#"
15
+
16
+ def process(message)
17
+ puts "Received message #{message.payload}"
18
+ end
19
+ end
20
+
21
+ MessageQueue.connect(:adapter => :bunny, :serializer => :json)
22
+ MessageQueue.run_consumables
23
+
24
+ Producer.new.publish(Time.now.to_s)
25
+
26
+ sleep 1
27
+
28
+ MessageQueue.disconnect
@@ -10,6 +10,10 @@ module MessageQueue
10
10
  instance.new_connection(serializer, options)
11
11
  end
12
12
  end
13
+
14
+ def new_connection(serializer, options = {})
15
+ Connection.new(serializer, options)
16
+ end
13
17
  end
14
18
  end
15
19
  end
@@ -1,25 +1,13 @@
1
- class MessageQueue::Adapters::Bunny::Connection
2
- attr_reader :serializer, :settings, :connection
3
-
4
- # Public: Initialize a new Bunny connection.
5
- #
6
- # serializer - The Serializer for dumping and loading payload.
7
- #
8
- # settings - The Hash settings used to connect with Bunny.
9
- # Details in http://rubybunny.info/articles/connecting.html.
10
- #
11
- # Returns a Connection wrapper for Bunny.
12
- def initialize(serializer, settings)
13
- @serializer = serializer
14
- @settings = settings
15
- end
1
+ class MessageQueue::Adapters::Bunny::Connection < MessageQueue::Connection
2
+ attr_reader :connection
16
3
 
17
4
  # Public: Connect to RabbitMQ
18
5
  #
19
6
  # Returns the Bunny instance
20
7
  def connect
21
8
  @connection ||= begin
22
- bunny = ::Bunny.new(settings)
9
+ super
10
+ bunny = ::Bunny.new(bunny_settings)
23
11
  bunny.start
24
12
  bunny
25
13
  end
@@ -30,27 +18,23 @@ class MessageQueue::Adapters::Bunny::Connection
30
18
  # Returns nothing
31
19
  def disconnect
32
20
  if @connection
21
+ super
33
22
  @connection.close if @connection.open?
34
23
  @connection = nil
35
24
  end
36
25
  end
37
26
 
38
- # Public: Connect to RabbitMQ, execute the block and disconnect
27
+ # Public: Check if it's connected to the message queue
39
28
  #
40
- # Returns nothing
41
- def with_connection(&block)
42
- begin
43
- connect
44
- block.call(self)
45
- ensure
46
- disconnect
47
- end
29
+ # Returns true if it's connected
30
+ def connected?
31
+ @connection.open? if @connection
48
32
  end
49
33
 
50
- def new_publisher(options)
34
+ def new_producer(options)
51
35
  raise "No connection to RabbitMQ" unless connection
52
36
 
53
- Publisher.new(self, options)
37
+ Producer.new(self, options)
54
38
  end
55
39
 
56
40
  def new_consumer(options)
@@ -58,7 +42,21 @@ class MessageQueue::Adapters::Bunny::Connection
58
42
 
59
43
  Consumer.new(self, options)
60
44
  end
45
+
46
+ private
47
+
48
+ def bunny_settings
49
+ default_bunny_settings.merge(settings)
50
+ end
51
+
52
+ def default_bunny_settings
53
+ {
54
+ :heartbeat => 1,
55
+ :automatically_recover => true,
56
+ :network_recovery_interval => 1
57
+ }
58
+ end
61
59
  end
62
60
 
63
- require "message_queue/adapters/bunny/publisher"
61
+ require "message_queue/adapters/bunny/producer"
64
62
  require "message_queue/adapters/bunny/consumer"
@@ -1,5 +1,4 @@
1
- class MessageQueue::Adapters::Bunny::Connection::Consumer
2
- attr_reader :connection
1
+ class MessageQueue::Adapters::Bunny::Connection::Consumer < MessageQueue::Consumer
3
2
  attr_reader :queue_options, :queue_name
4
3
  attr_reader :exchange_options, :exchange_name, :exchange_routing_key
5
4
  attr_reader :subscribe_options
@@ -25,27 +24,34 @@ class MessageQueue::Adapters::Bunny::Connection::Consumer
25
24
  #
26
25
  # Returns a Consumer.
27
26
  def initialize(connection, options = {})
28
- @connection = connection
27
+ super
29
28
 
30
- options = options.dup
31
-
32
- @queue_options = options.fetch(:queue)
29
+ @queue_options = self.options.fetch(:queue)
33
30
  @queue_name = queue_options.delete(:name) || (raise "Missing queue name")
34
31
 
35
- @exchange_options = options.fetch(:exchange)
32
+ @exchange_options = self.options.fetch(:exchange)
36
33
  @exchange_name = exchange_options.delete(:name) || (raise "Missing exchange name")
37
34
  @exchange_routing_key = exchange_options.delete(:routing_key) || queue_name
38
35
 
39
- @subscribe_options = options.fetch(:subscribe, {})
36
+ @subscribe_options = self.options.fetch(:subscribe, {}).merge(:ack => true)
40
37
  end
41
38
 
42
39
  def subscribe(options = {}, &block)
43
40
  @subscription = queue.subscribe(subscribe_options.merge(options)) do |delivery_info, metadata, payload|
44
- block.call(delivery_info, metadata, connection.serializer.load(payload))
41
+ begin
42
+ message = MessageQueue::Message.new(:message_id => metadata[:message_id],
43
+ :type => metadata[:type],
44
+ :timestamp => metadata[:timestamp],
45
+ :routing_key => delivery_info[:routing_key],
46
+ :payload => load_object(payload))
47
+ block.call(message)
48
+ ensure
49
+ ack(delivery_info.delivery_tag)
50
+ end
45
51
  end
46
52
  end
47
53
 
48
- def unsubscribe
54
+ def unsubscribe(options = {})
49
55
  @subscription.cancel if @subscription
50
56
  end
51
57
 
@@ -53,9 +59,13 @@ class MessageQueue::Adapters::Bunny::Connection::Consumer
53
59
  @queue ||= channel.queue(queue_name, queue_options).bind(exchange_name, :routing_key => exchange_routing_key)
54
60
  end
55
61
 
62
+ def ack(delivery_tag)
63
+ channel.ack(delivery_tag, false)
64
+ end
65
+
56
66
  private
57
67
 
58
68
  def channel
59
- connection.connection.create_channel
69
+ @channel ||= connection.connection.create_channel
60
70
  end
61
71
  end
@@ -1,13 +1,13 @@
1
- class MessageQueue::Adapters::Bunny::Connection::Publisher
2
- attr_reader :connection, :exchange
1
+ class MessageQueue::Adapters::Bunny::Connection::Producer < MessageQueue::Producer
2
+ attr_reader :exchange
3
3
  attr_reader :exchange_options, :exchange_name, :exchange_type
4
4
  attr_reader :message_options
5
5
 
6
- # Public: Initialize a new Bunny publisher.
6
+ # Public: Initialize a new Bunny producer.
7
7
  #
8
8
  # connection - The Bunny Connection.
9
9
  # options - The Hash options used to initialize the exchange
10
- # of a publisher:
10
+ # of a producer:
11
11
  # :exchange -
12
12
  # :name - The String exchange name.
13
13
  # :type - The Symbol exchange type.
@@ -21,20 +21,20 @@ class MessageQueue::Adapters::Bunny::Connection::Publisher
21
21
  #
22
22
  # Returns a Publisher.
23
23
  def initialize(connection, options = {})
24
- @connection = connection
24
+ super
25
25
 
26
- options = options.dup
27
-
28
- @exchange_options = options.fetch(:exchange)
26
+ @exchange_options = self.options.fetch(:exchange)
29
27
  @exchange_name = exchange_options.delete(:name) || (raise "Missing exchange name")
30
28
  @exchange_type = exchange_options.delete(:type) || (raise "Missing exchange type")
31
29
 
32
- @message_options = options.fetch(:message)
30
+ @message_options = self.options.fetch(:message)
33
31
 
34
- @exchange = connection.connection.create_channel.send(exchange_type, exchange_name, exchange_options)
32
+ @exchange = connection.connection.default_channel.send(exchange_type, exchange_name, exchange_options)
35
33
  end
36
34
 
37
- def publish(payload, options = {})
38
- exchange.publish(connection.serializer.dump(payload), message_options.merge(options))
35
+ def publish(object, options = {})
36
+ options = message_options.merge(default_options).merge(options)
37
+ object = dump_object(object)
38
+ exchange.publish(object, options)
39
39
  end
40
40
  end
@@ -0,0 +1,12 @@
1
+ class MessageQueue::Adapters::Memory::Connection < MessageQueue::Connection
2
+ def new_producer(options = {})
3
+ Producer.new(self, options)
4
+ end
5
+
6
+ def new_consumer(options = {})
7
+ Consumer.new(self, options)
8
+ end
9
+ end
10
+
11
+ require "message_queue/adapters/memory/producer"
12
+ require "message_queue/adapters/memory/consumer"
@@ -0,0 +1,34 @@
1
+ class MessageQueue::Adapters::Memory::Connection::Consumer < MessageQueue::Consumer
2
+ attr_reader :queue, :block
3
+
4
+ def initialize(*args)
5
+ super
6
+ @queue = []
7
+ end
8
+
9
+ def subscribe(options = {}, &block)
10
+ producer = options.fetch(:producer)
11
+ producer.add_observer(self)
12
+ @block = block
13
+ end
14
+
15
+ def unsubscribe(options = {})
16
+ producer = options.fetch(:producer)
17
+ producer.delete_observer(self)
18
+ @block = nil
19
+ end
20
+
21
+ def update(object, options)
22
+ object = load_object(object)
23
+ message = MessageQueue::Message.new(:message_id => options[:message_id],
24
+ :type => options[:type],
25
+ :timestamp => options[:timestamp],
26
+ :routing_key => options[:routing_key],
27
+ :payload => load_object(object))
28
+ if block
29
+ block.call(message)
30
+ else
31
+ queue << message
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,11 @@
1
+ require "observer"
2
+
3
+ class MessageQueue::Adapters::Memory::Connection::Producer < MessageQueue::Producer
4
+ include Observable
5
+
6
+ def publish(object, options = {})
7
+ changed
8
+ notify_observers(dump_object(object), default_options.merge(options))
9
+ true
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ module MessageQueue
2
+ module Adapters
3
+ class Memory < Adapter
4
+ def new_connection(serializer, options = {})
5
+ Connection.new(serializer, options)
6
+ end
7
+ end
8
+ end
9
+ end
10
+
11
+ require "message_queue/adapters/memory/connection"
@@ -0,0 +1,64 @@
1
+ require "message_queue/logging"
2
+
3
+ class MessageQueue::Connection
4
+ include MessageQueue::Logging
5
+
6
+ attr_reader :serializer, :settings
7
+
8
+ # Public: Initialize a new Bunny connection.
9
+ #
10
+ # serializer - The Serializer for dumping and loading payload.
11
+ #
12
+ # settings - The Hash settings used to connect.
13
+ #
14
+ #
15
+ # Returns a Connection wrapper for Bunny.
16
+ def initialize(serializer, settings)
17
+ @serializer = serializer
18
+ @settings = settings
19
+ end
20
+
21
+ # Public: Connect to the message queue
22
+ #
23
+ # Returns nothing
24
+ def connect
25
+ logger.info("Connecting to message queue with adapter #{self.class} and settings #{settings}")
26
+ end
27
+
28
+ # Public: Disconnect from the message queue
29
+ #
30
+ # Returns nothing
31
+ def disconnect
32
+ logger.info("Disconnecting from message queue")
33
+ end
34
+
35
+ # Public: Check if it's connected to the message queue
36
+ #
37
+ # Returns true if it's connected
38
+ def connected?
39
+ false
40
+ end
41
+
42
+ # Public: Connect to the message, execute the block and disconnect
43
+ #
44
+ # Returns nothing
45
+ def with_connection(&block)
46
+ begin
47
+ connect
48
+ block.call(self)
49
+ ensure
50
+ disconnect
51
+ end
52
+ end
53
+
54
+ def new_producer(options = {})
55
+ Producer.new(self, options)
56
+ end
57
+
58
+ def new_consumer(options = {})
59
+ Consumer.new(self, options)
60
+ end
61
+ end
62
+
63
+ require "message_queue/producer"
64
+ require "message_queue/consumer"
@@ -0,0 +1,83 @@
1
+ require "message_queue/logging"
2
+
3
+ module MessageQueue
4
+ # A module to mix in a consumer class, for example:
5
+ #
6
+ # class Consumer
7
+ # include MessageQueue::Consumable
8
+ #
9
+ # queue :name => "print_time_now"
10
+ # exchange :name => "time", :routing_key => "time.#"
11
+ #
12
+ # def process(message)
13
+ # ...
14
+ # end
15
+ # end
16
+ #
17
+ # The consumer class needs to implement the process method which will be passed
18
+ # a MessageQueue::Message instance when it receives a message.
19
+ module Consumable
20
+ include Logging
21
+
22
+ def self.included(base)
23
+ base.extend(ClassMethods)
24
+ MessageQueue.register_consumable(base)
25
+ end
26
+
27
+ module ClassMethods
28
+ def queue(options = {})
29
+ queue_options.merge!(options)
30
+ end
31
+
32
+ def exchange(options = {})
33
+ exchange_options.merge!(options)
34
+ end
35
+
36
+ def subscribe(options = {})
37
+ subscribe_options.merge!(options)
38
+ end
39
+
40
+ def queue_options
41
+ @queue_options ||= {}
42
+ end
43
+
44
+ def exchange_options
45
+ @exchange_options ||= {}
46
+ end
47
+
48
+ def subscribe_options
49
+ @subscribe_options ||= {}
50
+ end
51
+ end
52
+
53
+ def initialize
54
+ @consumer = MessageQueue.new_consumer(:queue => self.class.queue_options,
55
+ :exchange => self.class.exchange_options,
56
+ :subscribe => self.class.subscribe_options)
57
+ end
58
+
59
+ def subscribe(options = {})
60
+ @consumer.subscribe(options) do |message|
61
+ begin
62
+ logger.info("Message(#{message.message_id || '-'}): " +
63
+ "routing key: #{message.routing_key}, " +
64
+ "type: #{message.type}, " +
65
+ "timestamp: #{message.timestamp}, " +
66
+ "consumer: #{@consumer.class}, " +
67
+ "payload: #{message.payload}")
68
+ process(message)
69
+ rescue StandardError => ex
70
+ handle_error(message, consumer, ex)
71
+ end
72
+ end
73
+ end
74
+
75
+ private
76
+
77
+ def handle_error(message, consumer, ex)
78
+ MessageQueue.error_handlers.each do |handler|
79
+ handler.handle(message, consumer, ex)
80
+ end
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,28 @@
1
+ module MessageQueue
2
+ class ConsumableRunner
3
+ include Logging
4
+
5
+ attr_reader :consumables
6
+
7
+ def initialize(consumables)
8
+ @consumables = consumables
9
+ end
10
+
11
+ def run(options = {})
12
+ begin
13
+ block = !!options[:block]
14
+ consumables.each_with_index do |consumable, index|
15
+ # Blocks the last consumer
16
+ opts = if index < consumables.size - 1
17
+ {}
18
+ else
19
+ { :block => block }
20
+ end
21
+ consumable.new.subscribe(opts)
22
+ end
23
+ rescue SignalException => ex
24
+ logger.info "Received Signal #{ex}"
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,18 @@
1
+ require "message_queue/options_helper"
2
+
3
+ module MessageQueue
4
+ class Consumer
5
+ include OptionsHelper
6
+
7
+ attr_reader :connection, :options
8
+
9
+ def initialize(connection, options = {})
10
+ @connection = connection
11
+ @options = deep_clone(options)
12
+ end
13
+
14
+ def load_object(object)
15
+ connection.serializer.load(object)
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,19 @@
1
+ begin
2
+ require "airbrake"
3
+ rescue LoadError
4
+ end
5
+
6
+ if defined?(Airbrake)
7
+ module MessageQueue
8
+ module ErrorHandlers
9
+ class Airbrake
10
+ def handle(message, consumer, ex)
11
+ params = message.attributes.merge(:pid => Process.pid, :consumer => consumer.inspect)
12
+ ::Airbrake.notify_or_ignore(ex, :parameters => params)
13
+ end
14
+ end
15
+ end
16
+ end
17
+
18
+ MessageQueue.register_error_handler MessageQueue::ErrorHandlers::Airbrake.new
19
+ end