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 +4 -4
- data/lib/eventq_aws/aws_queue_client.rb +7 -2
- data/lib/eventq_aws/aws_queue_worker.rb +8 -4
- data/lib/eventq_aws/aws_queue_worker_v2.rb +298 -0
- data/lib/eventq_aws/version.rb +1 -1
- data/lib/eventq_aws.rb +1 -0
- metadata +19 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 060f06ea588d381244367abedaaefa6fa57c6878
|
4
|
+
data.tar.gz: 963b83f40dc3d8a00a4e05804912cf8210e23990
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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(
|
248
|
-
|
249
|
-
|
250
|
-
|
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
|
data/lib/eventq_aws/version.rb
CHANGED
data/lib/eventq_aws.rb
CHANGED
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.
|
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-
|
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.
|
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.
|
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
|