eventq_aws 1.16.2 → 1.17.0
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.
- 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
|