eventq 2.0.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
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
+