eventq_aws 1.16.2 → 1.17.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: e15c0b3ea491947a4e5b4def3a7f51bc4d67931e
4
- data.tar.gz: a7de217ebfaa2ff6fb60c9f3ed24502157a48342
3
+ metadata.gz: 060f06ea588d381244367abedaaefa6fa57c6878
4
+ data.tar.gz: 963b83f40dc3d8a00a4e05804912cf8210e23990
5
5
  SHA512:
6
- metadata.gz: 05c258c6081057650aacc7731d464f676bf6f0871938cb2316644948455289470b49ff57e3ed0210dbb59e41b701841919548bf2e778c98a2b7817061b06528a
7
- data.tar.gz: f1f95c3991299bcc67177e3c5158a67fd616a275568e9ae295752047e1b75fc9d7becdc1a17af3d27220949cb80157abc202d597f5bae386868a6c9004df3e9c
6
+ metadata.gz: 62ef5a2468dddb4685ac4e8f486603619a4d86d56ab2cc6babe7255fb6224e439e2202e7358169233f00df0aab867f5525c940f128802d75758c32c71a1b03d9
7
+ data.tar.gz: 958c3cad03b6408dabd2421e224f8b2236a8a0e26e6ede2281e09fb3d6de6b92f8668ec2982a1d060af49ad1f199cb19e231b4c098bbeae8500b5fb1b7269c30
@@ -13,6 +13,9 @@ module EventQ
13
13
 
14
14
  @aws_account = options[:aws_account_number]
15
15
 
16
+ @sns_keep_alive_timeout = options[:sns_keep_alive_timeout] || 30
17
+ @sns_continue_timeout = options[:sns_continue_timeout] || 15
18
+
16
19
  if options.has_key?(:aws_region)
17
20
  @aws_region = options[:aws_region]
18
21
  Aws.config[:region] = @aws_region
@@ -28,7 +31,10 @@ module EventQ
28
31
 
29
32
  # Returns the AWS SNS Client
30
33
  def sns
31
- @sns ||= Aws::SNS::Client.new
34
+ @sns ||= Aws::SNS::Client.new(
35
+ http_idle_timeout: @sns_keep_alive_timeout,
36
+ http_continue_timeout: @sns_continue_timeout
37
+ )
32
38
  end
33
39
 
34
40
  def get_topic_arn(event_type)
@@ -62,7 +68,6 @@ module EventQ
62
68
  def aws_safe_name(name)
63
69
  return name[0..79].gsub(/[^a-zA-Z\d_\-]/,'')
64
70
  end
65
-
66
71
  end
67
72
  end
68
73
  end
@@ -244,10 +244,14 @@ module EventQ
244
244
  payload = JSON.load(msg.body)
245
245
  message = deserialize_message(payload[MESSAGE])
246
246
 
247
- message_args = EventQ::MessageArgs.new(type: message.type,
248
- retry_attempts: retry_attempts,
249
- context: message.context,
250
- content_type: message.content_type)
247
+ message_args = EventQ::MessageArgs.new(
248
+ type: message.type,
249
+ retry_attempts: retry_attempts,
250
+ context: message.context,
251
+ content_type: message.content_type,
252
+ id: message.id,
253
+ sent: message.created
254
+ )
251
255
 
252
256
  EventQ.logger.info("[#{self.class}] - Message received. Retry Attempts: #{retry_attempts}")
253
257
 
@@ -0,0 +1,298 @@
1
+ require 'aws-sdk'
2
+
3
+ module EventQ
4
+ module Amazon
5
+ class QueueWorkerV2
6
+ include EventQ::WorkerId
7
+
8
+ APPROXIMATE_RECEIVE_COUNT = 'ApproximateReceiveCount'.freeze
9
+ MESSAGE = 'Message'.freeze
10
+
11
+ attr_accessor :is_running
12
+
13
+ def initialize
14
+ @forks = []
15
+ @is_running = false
16
+
17
+ @on_retry_exceeded_block = nil
18
+ @on_retry_block = nil
19
+ @on_error_block = nil
20
+
21
+ @hash_helper = HashKit::Helper.new
22
+ @serialization_provider_manager = EventQ::SerializationProviders::Manager.new
23
+ @signature_provider_manager = EventQ::SignatureProviders::Manager.new
24
+
25
+ @queue_poll_wait = 10
26
+ end
27
+
28
+ def start(queue, options = {}, &block)
29
+
30
+ EventQ.logger.info("[#{self.class}] - Preparing to start listening for messages.")
31
+
32
+ configure(queue, options)
33
+
34
+ if options[:client] == nil
35
+ raise "[#{self.class}] - :client (QueueClient) must be specified."
36
+ end
37
+
38
+ raise "[#{self.class}] - Worker is already running." if running?
39
+
40
+ client = options[:client]
41
+ EventQ.logger.debug do
42
+ "[#{self.class} #start] - Listening for messages on queue: #{queue.name}, Queue Url: #{client.get_queue_url(queue)}, Queue arn: #{client.get_queue_arn(queue)}"
43
+ end
44
+
45
+ EventQ.logger.info("[#{self.class}] - Listening for messages.")
46
+
47
+ @forks = []
48
+
49
+ if @fork_count > 1
50
+ Thread.new do
51
+ @fork_count.times do
52
+ pid = fork do
53
+ start_process(options, queue, block)
54
+ end
55
+ @forks.push(pid)
56
+ end
57
+ @forks.each { |pid| Process.wait(pid) }
58
+ end
59
+ else
60
+ start_process(options, queue, block)
61
+ end
62
+
63
+ return true
64
+ end
65
+
66
+ def start_process(options, queue, block)
67
+
68
+ %w'INT TERM'.each do |sig|
69
+ Signal.trap(sig) {
70
+ stop
71
+ exit
72
+ }
73
+ end
74
+
75
+ @is_running = true
76
+
77
+ Thread.new do
78
+ client = options[:client]
79
+ manager = EventQ::Amazon::QueueManager.new({ client: client })
80
+
81
+ queue_url = manager.get_queue(queue)
82
+ poller = Aws::SQS::QueuePoller.new(queue_url, attribute_names: [APPROXIMATE_RECEIVE_COUNT])
83
+
84
+ poller.poll(skip_delete: true) do |msg, stats|
85
+ begin
86
+ tag_processing_thread
87
+ process_message(msg, poller, queue, block)
88
+ rescue => e
89
+ EventQ.logger.error do
90
+ "[#{self.class}] - An unhandled error occurred. Error: #{e} | Backtrace: #{e.backtrace}"
91
+ end
92
+ call_on_error_block(error: e)
93
+ ensure
94
+ untag_processing_thread
95
+ end
96
+ end
97
+ end
98
+
99
+ if (options.key?(:wait) && options[:wait] == true) || (options.key?(:fork_count) && options[:fork_count] > 1)
100
+ while running? do
101
+ sleep 5
102
+ end
103
+ end
104
+ end
105
+
106
+ def call_on_error_block(error:, message: nil)
107
+ if @on_error_block
108
+ EventQ.logger.debug { "[#{self.class}] - Executing on_error block." }
109
+ begin
110
+ @on_error_block.call(error, message)
111
+ rescue => e
112
+ EventQ.logger.error("[#{self.class}] - An error occurred executing the on_error block. Error: #{e}")
113
+ end
114
+ else
115
+ EventQ.logger.debug { "[#{self.class}] - No on_error block specified to execute." }
116
+ end
117
+ end
118
+
119
+ def call_on_retry_exceeded_block(message)
120
+ if @on_retry_exceeded_block != nil
121
+ EventQ.logger.debug { "[#{self.class}] - Executing on_retry_exceeded block." }
122
+ begin
123
+ @on_retry_exceeded_block.call(message)
124
+ rescue => e
125
+ EventQ.logger.error("[#{self.class}] - An error occurred executing the on_retry_exceeded block. Error: #{e}")
126
+ end
127
+ else
128
+ EventQ.logger.debug { "[#{self.class}] - No on_retry_exceeded block specified." }
129
+ end
130
+ end
131
+
132
+ def call_on_retry_block(message)
133
+ if @on_retry_block
134
+ EventQ.logger.debug { "[#{self.class}] - Executing on_retry block." }
135
+ begin
136
+ @on_retry_block.call(message, abort)
137
+ rescue => e
138
+ EventQ.logger.error("[#{self.class}] - An error occurred executing the on_retry block. Error: #{e}")
139
+ end
140
+ else
141
+ EventQ.logger.debug { "[#{self.class}] - No on_retry block specified." }
142
+ end
143
+ end
144
+
145
+ def stop
146
+ EventQ.logger.info("[#{self.class}] - Stopping.")
147
+ @is_running = false
148
+ return true
149
+ end
150
+
151
+ def on_retry_exceeded(&block)
152
+ @retry_exceeded_block = block
153
+ end
154
+
155
+ def on_retry(&block)
156
+ @on_retry_block = block
157
+ return nil
158
+ end
159
+
160
+ def on_error(&block)
161
+ @on_error_block = block
162
+ return nil
163
+ end
164
+
165
+ def running?
166
+ return @is_running
167
+ end
168
+
169
+ def deserialize_message(payload)
170
+ provider = @serialization_provider_manager.get_provider(EventQ::Configuration.serialization_provider)
171
+ return provider.deserialize(payload)
172
+ end
173
+
174
+ def serialize_message(msg)
175
+ provider = @serialization_provider_manager.get_provider(EventQ::Configuration.serialization_provider)
176
+ return provider.serialize(msg)
177
+ end
178
+
179
+ private
180
+
181
+ def process_message(msg, poller, queue, block)
182
+ retry_attempts = msg.attributes[APPROXIMATE_RECEIVE_COUNT].to_i - 1
183
+
184
+ # deserialize the message payload
185
+ payload = JSON.load(msg.body)
186
+ message = deserialize_message(payload[MESSAGE])
187
+
188
+ message_args = EventQ::MessageArgs.new(
189
+ type: message.type,
190
+ retry_attempts: retry_attempts,
191
+ context: message.context,
192
+ content_type: message.content_type,
193
+ id: message.id,
194
+ sent: message.created
195
+ )
196
+
197
+ EventQ.logger.info("[#{self.class}] - Message received. Retry Attempts: #{retry_attempts}")
198
+
199
+ @signature_provider_manager.validate_signature(message: message, queue: queue)
200
+
201
+ if(!EventQ::NonceManager.is_allowed?(message.id))
202
+ EventQ.logger.info("[#{self.class}] - Duplicate Message received. Ignoring message.")
203
+ return false
204
+ end
205
+
206
+ # begin worker block for queue message
207
+ begin
208
+
209
+ block.call(message.content, message_args)
210
+
211
+ if message_args.abort == true
212
+ EventQ.logger.info("[#{self.class}] - Message aborted.")
213
+ else
214
+ # accept the message as processed
215
+ poller.delete_message(msg)
216
+ EventQ.logger.info("[#{self.class}] - Message acknowledged.")
217
+ end
218
+
219
+ rescue => e
220
+ EventQ.logger.error("[#{self.class}] - An unhandled error happened while attempting to process a queue message. Error: #{e} | Backtrace: #{e.backtrace}")
221
+ error = true
222
+ call_on_error_block(error: e, message: message)
223
+ end
224
+
225
+ if message_args.abort || error
226
+ EventQ::NonceManager.failed(message.id)
227
+ reject_message(queue, poller, msg, retry_attempts, message, message_args.abort)
228
+ else
229
+ EventQ::NonceManager.complete(message.id)
230
+ end
231
+
232
+ return true
233
+ end
234
+
235
+ def reject_message(queue, poller, msg, retry_attempts, message, abort)
236
+ if !queue.allow_retry || retry_attempts >= queue.max_retry_attempts
237
+ EventQ.logger.info("[#{self.class}] - Message rejected removing from queue. Message: #{serialize_message(message)}")
238
+
239
+ # remove the message from the queue so that it does not get retried again
240
+ poller.delete_message(msg)
241
+
242
+ if retry_attempts >= queue.max_retry_attempts
243
+ EventQ.logger.info("[#{self.class}] - Message retry attempt limit exceeded.")
244
+ call_on_retry_exceeded_block(message)
245
+ end
246
+ elsif queue.allow_retry
247
+ retry_attempts += 1
248
+
249
+ EventQ.logger.info("[#{self.class}] - Message rejected requesting retry. Attempts: #{retry_attempts}")
250
+
251
+ if queue.allow_retry_back_off == true
252
+ EventQ.logger.debug { "[#{self.class}] - Calculating message back off retry delay. Attempts: #{retry_attempts} * Delay: #{queue.retry_delay}" }
253
+ visibility_timeout = (queue.retry_delay * retry_attempts) / 1000
254
+ if visibility_timeout > (queue.max_retry_delay / 1000)
255
+ EventQ.logger.debug { "[#{self.class}] - Max message back off retry delay reached." }
256
+ visibility_timeout = queue.max_retry_delay / 1000
257
+ end
258
+ else
259
+ EventQ.logger.debug { "[#{self.class}] - Setting fixed retry delay for message." }
260
+ visibility_timeout = queue.retry_delay / 1000
261
+ end
262
+
263
+ if visibility_timeout > 43200
264
+ EventQ.logger.debug { "[#{self.class}] - AWS max visibility timeout of 12 hours has been exceeded. Setting message retry delay to 12 hours." }
265
+ visibility_timeout = 43200
266
+ end
267
+
268
+ EventQ.logger.debug { "[#{self.class}] - Sending message for retry. Message TTL: #{visibility_timeout}" }
269
+ poller.change_message_visibility_timeout(msg, visibility_timeout)
270
+
271
+ call_on_retry_block(message)
272
+ end
273
+
274
+ end
275
+
276
+ def configure(queue, options = {})
277
+ @queue = queue
278
+
279
+ if options.key?(:thread_count)
280
+ EventQ.logger.warn("[#{self.class}] - :thread_count is deprecated.")
281
+ end
282
+
283
+ if options.key?(:sleep)
284
+ EventQ.logger.warn("[#{self.class}] - :sleep is deprecated.")
285
+ end
286
+
287
+ @fork_count = 1
288
+ if options.key?(:fork_count)
289
+ @fork_count = options[:fork_count]
290
+ end
291
+
292
+ EventQ.logger.info("[#{self.class}] - Configuring. Process Count: #{@fork_count}.")
293
+
294
+ return true
295
+ end
296
+ end
297
+ end
298
+ end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module EventQ
4
4
  module Amazon
5
- VERSION = "1.16.2"
5
+ VERSION = "1.17.0"
6
6
  end
7
7
  end
data/lib/eventq_aws.rb CHANGED
@@ -12,6 +12,7 @@ if RUBY_PLATFORM =~ /java/
12
12
  require 'eventq_aws/jruby/aws_queue_worker'
13
13
  else
14
14
  require 'eventq_aws/aws_queue_worker'
15
+ require 'eventq_aws/aws_queue_worker_v2'
15
16
  end
16
17
 
17
18
  module EventQ
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: eventq_aws
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.16.2
4
+ version: 1.17.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - vaughanbrittonsage
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-03-30 00:00:00.000000000 Z
11
+ date: 2018-03-31 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -66,20 +66,34 @@ dependencies:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
68
  version: '2.0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: aws-sdk
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '2.0'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '2.0'
69
83
  - !ruby/object:Gem::Dependency
70
84
  name: eventq_base
71
85
  requirement: !ruby/object:Gem::Requirement
72
86
  requirements:
73
87
  - - "~>"
74
88
  - !ruby/object:Gem::Version
75
- version: '1.15'
89
+ version: '1.17'
76
90
  type: :runtime
77
91
  prerelease: false
78
92
  version_requirements: !ruby/object:Gem::Requirement
79
93
  requirements:
80
94
  - - "~>"
81
95
  - !ruby/object:Gem::Version
82
- version: '1.15'
96
+ version: '1.17'
83
97
  description: This is the aws implementation for EventQ
84
98
  email:
85
99
  - vaughan.britton@sage.com
@@ -94,6 +108,7 @@ files:
94
108
  - lib/eventq_aws/aws_queue_client.rb
95
109
  - lib/eventq_aws/aws_queue_manager.rb
96
110
  - lib/eventq_aws/aws_queue_worker.rb
111
+ - lib/eventq_aws/aws_queue_worker_v2.rb
97
112
  - lib/eventq_aws/aws_status_checker.rb
98
113
  - lib/eventq_aws/aws_subscription_manager.rb
99
114
  - lib/eventq_aws/jruby/aws_queue_worker.rb