eventq 2.0.0.rc1

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 (65) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +336 -0
  3. data/bin/console +14 -0
  4. data/bin/setup +8 -0
  5. data/lib/eventq/aws.rb +38 -0
  6. data/lib/eventq/eventq_aws/README.md +53 -0
  7. data/lib/eventq/eventq_aws/aws_eventq_client.rb +120 -0
  8. data/lib/eventq/eventq_aws/aws_queue_client.rb +64 -0
  9. data/lib/eventq/eventq_aws/aws_queue_manager.rb +68 -0
  10. data/lib/eventq/eventq_aws/aws_queue_worker.rb +168 -0
  11. data/lib/eventq/eventq_aws/aws_status_checker.rb +25 -0
  12. data/lib/eventq/eventq_aws/aws_subscription_manager.rb +65 -0
  13. data/lib/eventq/eventq_aws/jruby/aws_queue_worker.rb +370 -0
  14. data/lib/eventq/eventq_aws/sns.rb +64 -0
  15. data/lib/eventq/eventq_aws/sqs.rb +112 -0
  16. data/lib/eventq/eventq_base/configuration.rb +33 -0
  17. data/lib/eventq/eventq_base/event_raised_exchange.rb +7 -0
  18. data/lib/eventq/eventq_base/event_raised_queue.rb +7 -0
  19. data/lib/eventq/eventq_base/eventq_client_contract.rb +9 -0
  20. data/lib/eventq/eventq_base/eventq_logger.rb +28 -0
  21. data/lib/eventq/eventq_base/exceptions/invalid_signature_exception.rb +9 -0
  22. data/lib/eventq/eventq_base/exceptions/worker_thread_error.rb +10 -0
  23. data/lib/eventq/eventq_base/exceptions.rb +2 -0
  24. data/lib/eventq/eventq_base/exchange.rb +5 -0
  25. data/lib/eventq/eventq_base/message_args.rb +23 -0
  26. data/lib/eventq/eventq_base/nonce_manager.rb +57 -0
  27. data/lib/eventq/eventq_base/queue.rb +27 -0
  28. data/lib/eventq/eventq_base/queue_message.rb +31 -0
  29. data/lib/eventq/eventq_base/queue_worker_contract.rb +23 -0
  30. data/lib/eventq/eventq_base/serialization_providers/binary_serialization_provider.rb +15 -0
  31. data/lib/eventq/eventq_base/serialization_providers/jruby/oj/array_writer.rb +20 -0
  32. data/lib/eventq/eventq_base/serialization_providers/jruby/oj/attribute_writer.rb +24 -0
  33. data/lib/eventq/eventq_base/serialization_providers/jruby/oj/class_writer.rb +20 -0
  34. data/lib/eventq/eventq_base/serialization_providers/jruby/oj/date_time_writer.rb +33 -0
  35. data/lib/eventq/eventq_base/serialization_providers/jruby/oj/date_writer.rb +22 -0
  36. data/lib/eventq/eventq_base/serialization_providers/jruby/oj/hash_writer.rb +18 -0
  37. data/lib/eventq/eventq_base/serialization_providers/jruby/oj/rational_writer.rb +20 -0
  38. data/lib/eventq/eventq_base/serialization_providers/jruby/oj/serializer.rb +17 -0
  39. data/lib/eventq/eventq_base/serialization_providers/jruby/oj/time_writer.rb +18 -0
  40. data/lib/eventq/eventq_base/serialization_providers/jruby/oj/value_writer.rb +16 -0
  41. data/lib/eventq/eventq_base/serialization_providers/jruby/oj.rb +10 -0
  42. data/lib/eventq/eventq_base/serialization_providers/jruby/oj_serialization_provider.rb +25 -0
  43. data/lib/eventq/eventq_base/serialization_providers/jruby.rb +2 -0
  44. data/lib/eventq/eventq_base/serialization_providers/json_serialization_provider.rb +28 -0
  45. data/lib/eventq/eventq_base/serialization_providers/oj_serialization_provider.rb +24 -0
  46. data/lib/eventq/eventq_base/serialization_providers.rb +36 -0
  47. data/lib/eventq/eventq_base/signature_providers/sha256_signature_provider.rb +31 -0
  48. data/lib/eventq/eventq_base/signature_providers.rb +44 -0
  49. data/lib/eventq/eventq_base/subscription_manager_contract.rb +13 -0
  50. data/lib/eventq/eventq_base/version.rb +3 -0
  51. data/lib/eventq/eventq_base/worker_id.rb +20 -0
  52. data/lib/eventq/eventq_rabbitmq/README.md +36 -0
  53. data/lib/eventq/eventq_rabbitmq/default_queue.rb +12 -0
  54. data/lib/eventq/eventq_rabbitmq/jruby/rabbitmq_queue_worker.rb +367 -0
  55. data/lib/eventq/eventq_rabbitmq/rabbitmq_eventq_client.rb +140 -0
  56. data/lib/eventq/eventq_rabbitmq/rabbitmq_queue_client.rb +54 -0
  57. data/lib/eventq/eventq_rabbitmq/rabbitmq_queue_manager.rb +104 -0
  58. data/lib/eventq/eventq_rabbitmq/rabbitmq_queue_worker.rb +168 -0
  59. data/lib/eventq/eventq_rabbitmq/rabbitmq_status_checker.rb +62 -0
  60. data/lib/eventq/eventq_rabbitmq/rabbitmq_subscription_manager.rb +54 -0
  61. data/lib/eventq/queue_worker.rb +241 -0
  62. data/lib/eventq/rabbitmq.rb +49 -0
  63. data/lib/eventq/worker_status.rb +64 -0
  64. data/lib/eventq.rb +25 -0
  65. metadata +289 -0
@@ -0,0 +1,16 @@
1
+ module EventQ
2
+ module SerializationProviders
3
+ module JRuby
4
+ module Oj
5
+ class ValueWriter < AttributeWriter
6
+ def valid?(obj)
7
+ obj.is_a?(String) || obj.is_a?(Integer) || obj.is_a?(Float)
8
+ end
9
+ def exec(obj)
10
+ obj
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,10 @@
1
+ require_relative 'oj/attribute_writer'
2
+ require_relative 'oj/class_writer'
3
+ require_relative 'oj/rational_writer'
4
+ require_relative 'oj/date_time_writer'
5
+ require_relative 'oj/date_writer'
6
+ require_relative 'oj/time_writer'
7
+ require_relative 'oj/array_writer'
8
+ require_relative 'oj/hash_writer'
9
+ require_relative 'oj/value_writer'
10
+ require_relative 'oj/serializer'
@@ -0,0 +1,25 @@
1
+ module EventQ
2
+ module SerializationProviders
3
+ module JRuby
4
+ class OjSerializationProvider
5
+ def initialize
6
+ @json_serializer = EventQ::SerializationProviders::JsonSerializationProvider.new
7
+ @oj_serializer = Oj::Serializer.new
8
+ end
9
+
10
+ def serialize(object)
11
+ @oj_serializer.dump(object)
12
+ end
13
+
14
+ def deserialize(json)
15
+ begin
16
+ return @oj_serializer.load(json)
17
+ rescue
18
+ EventQ.log(:debug, "[#{self.class}] - Failed to deserialize using Oj, falling back to JsonSerializationProvider.")
19
+ return @json_serializer.deserialize(json)
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,2 @@
1
+ require_relative 'jruby/oj'
2
+ require_relative 'jruby/oj_serialization_provider'
@@ -0,0 +1,28 @@
1
+ module EventQ
2
+ module SerializationProviders
3
+ class JsonSerializationProvider
4
+
5
+ def initialize
6
+ require 'class_kit'
7
+ require 'hash_kit'
8
+ @class_kit_helper = ClassKit::Helper.new
9
+ @hash_helper = HashKit::Helper.new
10
+ end
11
+
12
+ def serialize(object)
13
+ JSON.dump(object_to_hash(object))
14
+ end
15
+
16
+ def deserialize(json)
17
+ return @class_kit_helper.from_json(json: json, klass: EventQ::QueueMessage)
18
+ end
19
+
20
+ private
21
+
22
+ def object_to_hash(object)
23
+ return object if object.is_a?(Hash)
24
+ @hash_helper.to_hash(object)
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,24 @@
1
+ module EventQ
2
+ module SerializationProviders
3
+ class OjSerializationProvider
4
+
5
+ def initialize
6
+ require 'oj'
7
+ @json_serializer = EventQ::SerializationProviders::JsonSerializationProvider.new
8
+ end
9
+
10
+ def serialize(object)
11
+ Oj.dump(object, mode: :object)
12
+ end
13
+
14
+ def deserialize(json)
15
+ begin
16
+ Oj.load(json)
17
+ rescue Oj::ParseError, ArgumentError
18
+ EventQ.log(:debug, "[#{self.class}] - Failed to deserialize using Oj, falling back to JsonSerializationProvider.")
19
+ @json_serializer.deserialize(json)
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,36 @@
1
+ require_relative 'serialization_providers/json_serialization_provider'
2
+ unless RUBY_PLATFORM =~ /java/
3
+ require_relative 'serialization_providers/oj_serialization_provider'
4
+ end
5
+ require_relative 'serialization_providers/jruby'
6
+ require_relative 'serialization_providers/binary_serialization_provider'
7
+
8
+ module EventQ
9
+ module SerializationProviders
10
+
11
+ OJ_PROVIDER = 'oj'.freeze
12
+ JSON_PROVIDER = 'json'.freeze
13
+ BINARY_PROVIDER = 'binary'.freeze
14
+
15
+ class Manager
16
+ def initialize
17
+ @providers = {}
18
+ if RUBY_PLATFORM =~ /java/
19
+ @providers[OJ_PROVIDER] = EventQ::SerializationProviders::JRuby::OjSerializationProvider
20
+ else
21
+ @providers[OJ_PROVIDER] = EventQ::SerializationProviders::OjSerializationProvider
22
+ end
23
+ @providers[JSON_PROVIDER] = EventQ::SerializationProviders::JsonSerializationProvider
24
+ @providers[BINARY_PROVIDER] = EventQ::SerializationProviders::BinarySerializationProvider
25
+ end
26
+
27
+ def get_provider(provider_type)
28
+ provider = @providers[provider_type]
29
+ if provider.nil?
30
+ raise "Invalid provider type specified: #{provider_type}"
31
+ end
32
+ return provider.new
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,31 @@
1
+ module EventQ
2
+ module SignatureProviders
3
+ class Sha256SignatureProvider
4
+
5
+ def initialize
6
+ require 'openssl'
7
+ require 'base64'
8
+ @serializer = serialization_provider_manager.get_provider(EventQ::Configuration.serialization_provider)
9
+ end
10
+
11
+ #This method is called to create a signature for a message
12
+ def write(message:, secret:)
13
+ json = @serializer.serialize(message.content)
14
+ hash = OpenSSL::HMAC.digest('sha256', secret, json)
15
+ Base64.encode64(hash)
16
+ end
17
+
18
+ #This method is called to validate a message signature
19
+ def valid?(message:, secret:)
20
+ signature = write(message: message, secret: secret)
21
+ message.signature == signature
22
+ end
23
+
24
+ private
25
+
26
+ def serialization_provider_manager
27
+ EventQ::SerializationProviders::Manager.new
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,44 @@
1
+ require_relative 'signature_providers/sha256_signature_provider'
2
+
3
+ module EventQ
4
+ module SignatureProviders
5
+
6
+ SHA256 = 'sha256'.freeze
7
+
8
+ class Manager
9
+ def initialize
10
+ @providers = {}
11
+ @providers[SHA256] = EventQ::SignatureProviders::Sha256SignatureProvider
12
+ end
13
+
14
+ #This method is called to get a signature provider
15
+ def get_provider(provider_type)
16
+ provider = @providers[provider_type]
17
+ if provider == nil
18
+ raise "Invalid provider type specified: #{provider_type}"
19
+ end
20
+ return provider.new
21
+ end
22
+
23
+ #This method is called to validate a queue message's signature
24
+ def validate_signature(message:, queue:)
25
+ valid = true
26
+
27
+ if queue.require_signature == true && message.signature == nil
28
+ valid = false
29
+ elsif message.signature != nil
30
+ provider = get_provider(EventQ::Configuration.signature_provider)
31
+ valid = provider.valid?(message: message, secret: EventQ::Configuration.signature_secret)
32
+ end
33
+
34
+ if !valid
35
+ raise EventQ::Exceptions::InvalidSignatureException.new
36
+ end
37
+
38
+ true
39
+
40
+ end
41
+
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,13 @@
1
+ module EventQ
2
+ class SubscriptionManagerContract
3
+
4
+ def subscribe(event_type, queue)
5
+
6
+ end
7
+
8
+ def unsubscribe(queue)
9
+
10
+ end
11
+
12
+ end
13
+ end
@@ -0,0 +1,3 @@
1
+ module EventqBase
2
+ VERSION = "1.18.0"
3
+ end
@@ -0,0 +1,20 @@
1
+ module EventQ
2
+ # Module to be used by concrete worker classes to tag each thread working on a message
3
+ # Allows to be used in custom logging to track group of log messages per queue message processing.
4
+ module WorkerId
5
+ def tag_processing_thread
6
+ Thread.current[key_name] = SecureRandom.uuid
7
+ end
8
+
9
+ def untag_processing_thread
10
+ Thread.current[key_name] = nil
11
+ end
12
+
13
+ private
14
+
15
+ def key_name
16
+ 'worker_id'.freeze
17
+ end
18
+
19
+ end
20
+ end
@@ -0,0 +1,36 @@
1
+ # EventQ [RabbitMq]
2
+
3
+ Welcome to EventQ. This gem contains the RabbitMq implementations of the EventQ framework components.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem 'eventq_rabbitmq'
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install eventq_rabbitmq
20
+
21
+
22
+ ## Development
23
+
24
+ After checking out the repo, run `bin/setup` to install dependencies. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
25
+
26
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
27
+
28
+ ## Contributing
29
+
30
+ Bug reports and pull requests are welcome on GitHub at https://github.com/sage/eventq. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
31
+
32
+
33
+ ## License
34
+
35
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
36
+
@@ -0,0 +1,12 @@
1
+ module EventQ
2
+ module RabbitMq
3
+ class DefaultQueue < Queue
4
+ def initialize
5
+ @name = 'Default'.freeze
6
+ @allow_retry = false
7
+ @max_retry_attempts = 1
8
+ end
9
+ end
10
+ end
11
+ end
12
+
@@ -0,0 +1,367 @@
1
+ require 'java'
2
+ java_import java.util.concurrent.Executors
3
+ module EventQ
4
+ module RabbitMq
5
+ class QueueWorker
6
+ include EventQ::WorkerId
7
+
8
+ attr_accessor :is_running
9
+
10
+ def initialize
11
+ @is_running = false
12
+
13
+ @retry_exceeded_block = nil
14
+ @on_retry_block = nil
15
+ @on_error_block = nil
16
+ @hash_helper = HashKit::Helper.new
17
+ @serialization_provider_manager = EventQ::SerializationProviders::Manager.new
18
+ @signature_provider_manager = EventQ::SignatureProviders::Manager.new
19
+ @last_gc_flush = Time.now
20
+ @gc_flush_interval = 10
21
+ end
22
+
23
+ def start(queue, options = {}, &block)
24
+
25
+ EventQ.logger.info("[#{self.class}] - Preparing to start listening for messages.")
26
+
27
+ configure(queue, options)
28
+
29
+ raise "[#{self.class}] - Worker is already running." if running?
30
+
31
+ if options[:client] == nil
32
+ raise "[#{self.class}] - :client (QueueClient) must be specified."
33
+ end
34
+
35
+ EventQ.logger.info("[#{self.class}] - Listening for messages.")
36
+ EventQ.logger.debug do
37
+ "[#{self.class} #start] - Listening for messages on queue: #{EventQ.create_queue_name(queue.name)}"
38
+ end
39
+
40
+ start_process(options, queue, block)
41
+
42
+ return true
43
+ end
44
+
45
+ def start_process(options, queue, block)
46
+
47
+ @is_running = true
48
+
49
+ %w'INT TERM'.each do |sig|
50
+ Signal.trap(sig) {
51
+ stop
52
+ exit
53
+ }
54
+ end
55
+
56
+ if !options.key?(:durable)
57
+ options[:durable] = true
58
+ end
59
+
60
+ client = options[:client]
61
+ manager = EventQ::RabbitMq::QueueManager.new
62
+ manager.durable = options[:durable]
63
+ @connection = client.get_connection
64
+
65
+ @executor = java.util.concurrent.Executors::newFixedThreadPool @thread_count
66
+
67
+ #loop through each thread count
68
+ @thread_count.times do
69
+
70
+ @executor.execute do
71
+
72
+ #begin the queue loop for this thread
73
+ while true do
74
+
75
+ #check if the worker is still allowed to run and break out of thread loop if not
76
+ unless running?
77
+ break
78
+ end
79
+
80
+ if @executor.is_shutdown
81
+ break
82
+ end
83
+
84
+ has_received_message = false
85
+
86
+ begin
87
+
88
+ channel = @connection.create_channel
89
+
90
+ has_received_message = thread_process_iteration(channel, manager, queue, block)
91
+
92
+ rescue => e
93
+ EventQ.logger.error("An unhandled error occurred. Error: #{e} | Backtrace: #{e.backtrace}")
94
+ call_on_error_block(error: e)
95
+ end
96
+
97
+ if channel != nil && channel.open?
98
+ channel.close
99
+ end
100
+
101
+ gc_flush
102
+
103
+ if !has_received_message
104
+ EventQ.logger.debug { "[#{self.class}] - No message received." }
105
+ if @sleep > 0
106
+ EventQ.logger.debug { "[#{self.class}] - Sleeping for #{@sleep} seconds" }
107
+ sleep(@sleep)
108
+ end
109
+ end
110
+
111
+ end
112
+
113
+ end
114
+
115
+ end
116
+
117
+ if options.key?(:wait) && options[:wait] == true
118
+ while running? do end
119
+ @connection.close if @connection.open?
120
+ end
121
+
122
+ return true
123
+
124
+ end
125
+
126
+ def call_on_error_block(error:, message: nil)
127
+ if @on_error_block
128
+ EventQ.logger.debug { "[#{self.class}] - Executing on_error block." }
129
+ begin
130
+ @on_error_block.call(error, message)
131
+ rescue => e
132
+ EventQ.logger.error("[#{self.class}] - An error occurred executing the on_error block. Error: #{e}")
133
+ end
134
+ else
135
+ EventQ.logger.debug { "[#{self.class}] - No on_error block specified to execute." }
136
+ end
137
+ end
138
+
139
+ def gc_flush
140
+ if Time.now - last_gc_flush > @gc_flush_interval
141
+ GC.start
142
+ @last_gc_flush = Time.now
143
+ end
144
+ end
145
+
146
+ def last_gc_flush
147
+ @last_gc_flush
148
+ end
149
+
150
+ def thread_process_iteration(channel, manager, queue, block)
151
+
152
+ #get the queue
153
+ q = manager.get_queue(channel, queue)
154
+ retry_exchange = manager.get_retry_exchange(channel, queue)
155
+
156
+ received = false
157
+
158
+ begin
159
+ delivery_info, payload = manager.pop_message(queue: q)
160
+
161
+ #check that message was received
162
+ if payload != nil
163
+ received = true
164
+ begin
165
+ tag_processing_thread
166
+ process_message(payload, queue, channel, retry_exchange, delivery_info, block)
167
+ ensure
168
+ untag_processing_thread
169
+ end
170
+
171
+ end
172
+
173
+ rescue => e
174
+ EventQ.logger.error("[#{self.class}] - An error occurred attempting to process a message. Error: #{e} | Backtrace: #{e.backtrace}")
175
+ call_on_error_block(error: e)
176
+ end
177
+
178
+ return received
179
+ end
180
+
181
+ def stop
182
+ EventQ.logger.info { "[#{self.class}] - Stopping..." }
183
+ @is_running = false
184
+ @executor.shutdown
185
+ if @connection != nil
186
+ @connection.close if @connection.open?
187
+ end
188
+ return true
189
+ end
190
+
191
+ def on_retry_exceeded(&block)
192
+ @retry_exceeded_block = block
193
+ return nil
194
+ end
195
+
196
+ def on_retry(&block)
197
+ @on_retry_block = block
198
+ return nil
199
+ end
200
+
201
+ def on_error(&block)
202
+ @on_error_block = block
203
+ return nil
204
+ end
205
+
206
+ def running?
207
+ return @is_running
208
+ end
209
+
210
+ def deserialize_message(payload)
211
+ provider = @serialization_provider_manager.get_provider(EventQ::Configuration.serialization_provider)
212
+ return provider.deserialize(payload)
213
+ end
214
+
215
+ def serialize_message(msg)
216
+ provider = @serialization_provider_manager.get_provider(EventQ::Configuration.serialization_provider)
217
+ return provider.serialize(msg)
218
+ end
219
+
220
+ def call_on_retry_exceeded_block(message)
221
+ if @retry_exceeded_block != nil
222
+ EventQ.logger.debug { "[#{self.class}] - Executing on_retry_exceeded block." }
223
+ begin
224
+ @retry_exceeded_block.call(message)
225
+ rescue => e
226
+ EventQ.logger.error("[#{self.class}] - An error occurred executing the on_retry_exceeded block. Error: #{e}")
227
+ end
228
+ else
229
+ EventQ.logger.debug { "[#{self.class}] - No on_retry_exceeded block specified." }
230
+ end
231
+ end
232
+
233
+ def call_on_retry_block(message)
234
+ if @on_retry_block
235
+ EventQ.logger.debug { "[#{self.class}] - Executing on_retry block." }
236
+ begin
237
+ @on_retry_block.call(message, abort)
238
+ rescue => e
239
+ EventQ.logger.error("[#{self.class}] - An error occurred executing the on_retry block. Error: #{e}")
240
+ end
241
+ else
242
+ EventQ.logger.debug { "[#{self.class}] - No on_retry block specified." }
243
+ end
244
+ end
245
+
246
+ def reject_message(channel, message, delivery_tag, retry_exchange, queue, abort)
247
+
248
+ EventQ.logger.info("[#{self.class}] - Message rejected removing from queue.")
249
+ #reject the message to remove from queue
250
+ channel.reject(delivery_tag, false)
251
+
252
+ #check if the message retry limit has been exceeded
253
+ if message.retry_attempts >= queue.max_retry_attempts
254
+
255
+ EventQ.logger.info("[#{self.class}] - Message retry attempt limit exceeded. Msg: #{serialize_message(message)}")
256
+
257
+ call_on_retry_exceeded_block(message)
258
+
259
+ #check if the message is allowed to be retried
260
+ elsif queue.allow_retry
261
+
262
+ EventQ.logger.debug { "[#{self.class}] - Incrementing retry attempts count." }
263
+ message.retry_attempts += 1
264
+
265
+ if queue.allow_retry_back_off == true
266
+ EventQ.logger.debug { "[#{self.class}] - Calculating message back off retry delay. Attempts: #{message.retry_attempts} * Retry Delay: #{queue.retry_delay}" }
267
+ message_ttl = message.retry_attempts * queue.retry_delay
268
+ if (message.retry_attempts * queue.retry_delay) > queue.max_retry_delay
269
+ EventQ.logger.debug { "[#{self.class}] - Max message back off retry delay reached." }
270
+ message_ttl = queue.max_retry_delay
271
+ end
272
+ else
273
+ EventQ.logger.debug { "[#{self.class}] - Setting fixed retry delay for message." }
274
+ message_ttl = queue.retry_delay
275
+ end
276
+
277
+ EventQ.logger.debug { "[#{self.class}] - Sending message for retry. Message TTL: #{message_ttl}" }
278
+ retry_exchange.publish(serialize_message(message), :expiration => message_ttl)
279
+ EventQ.logger.debug { "[#{self.class}] - Published message to retry exchange." }
280
+
281
+ call_on_retry_block(message)
282
+
283
+ end
284
+
285
+ return true
286
+
287
+ end
288
+
289
+ def configure(queue, options = {})
290
+
291
+ @queue = queue
292
+
293
+ #default thread count
294
+ @thread_count = 4
295
+ if options.key?(:thread_count)
296
+ @thread_count = options[:thread_count]
297
+ end
298
+
299
+ #default sleep time in seconds
300
+ @sleep = 15
301
+ if options.key?(:sleep)
302
+ @sleep = options[:sleep]
303
+ end
304
+
305
+ @gc_flush_interval = 10
306
+ if options.key?(:gc_flush_interval)
307
+ @gc_flush_interval = options[:gc_flush_interval]
308
+ end
309
+
310
+ EventQ.logger.info("[#{self.class}] - Configuring. Thread Count: #{@thread_count} | Interval Sleep: #{@sleep}.")
311
+
312
+ return true
313
+
314
+ end
315
+
316
+ private
317
+
318
+ def process_message(payload, queue, channel, retry_exchange, delivery_tag, block)
319
+ abort = false
320
+ error = false
321
+ message = deserialize_message(payload)
322
+
323
+ EventQ.logger.info("[#{self.class}] - Message received. Retry Attempts: #{message.retry_attempts}")
324
+
325
+ @signature_provider_manager.validate_signature(message: message, queue: queue)
326
+
327
+ message_args = EventQ::MessageArgs.new(type: message.type,
328
+ retry_attempts: message.retry_attempts,
329
+ context: message.context,
330
+ content_type: message.content_type)
331
+
332
+ if(!EventQ::NonceManager.is_allowed?(message.id))
333
+ EventQ.logger.info("[#{self.class}] - Duplicate Message received. Dropping message.")
334
+ channel.acknowledge(delivery_tag, false)
335
+ return false
336
+ end
337
+
338
+ #begin worker block for queue message
339
+ begin
340
+ block.call(message.content, message_args)
341
+
342
+ if message_args.abort == true
343
+ abort = true
344
+ EventQ.logger.info("[#{self.class}] - Message aborted.")
345
+ else
346
+ #accept the message as processed
347
+ channel.acknowledge(delivery_tag, false)
348
+ EventQ.logger.info("[#{self.class}] - Message acknowledged.")
349
+ end
350
+
351
+ rescue => e
352
+ EventQ.logger.error("[#{self.class}] - An unhandled error happened attempting to process a queue message. Error: #{e} | Backtrace: #{e.backtrace}")
353
+ error = true
354
+ call_on_error_block(error: e, message: message)
355
+ end
356
+
357
+ if error || abort
358
+ EventQ::NonceManager.failed(message.id)
359
+ reject_message(channel, message, delivery_tag, retry_exchange, queue, abort)
360
+ else
361
+ EventQ::NonceManager.complete(message.id)
362
+ end
363
+ end
364
+ end
365
+ end
366
+ end
367
+