eventq_aws 1.14.0-java
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 +7 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/lib/eventq_aws/aws_eventq_client.rb +116 -0
- data/lib/eventq_aws/aws_queue_client.rb +68 -0
- data/lib/eventq_aws/aws_queue_manager.rb +98 -0
- data/lib/eventq_aws/aws_queue_worker.rb +386 -0
- data/lib/eventq_aws/aws_status_checker.rb +25 -0
- data/lib/eventq_aws/aws_subscription_manager.rb +66 -0
- data/lib/eventq_aws/jruby/aws_queue_worker.rb +370 -0
- data/lib/eventq_aws/version.rb +5 -0
- data/lib/eventq_aws.rb +37 -0
- metadata +125 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 184374221348bf33be9f74cd8d4d8b0f26b9dea45056bd13f1eb930d03149a81
|
4
|
+
data.tar.gz: 3c5a842fed0e4e52ebf001b91a76348d5fb4f5c6db53ec516aaecaf523ed1b29
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: daea0b813cac8d208a55c6882bdcbf17f4e602779f6da0981be747d7ec8b88ca63734b7d625b2e5739b94b89f72f48fc5a2535c83f7d519805161016e8c5e840
|
7
|
+
data.tar.gz: 2a9121ab2e4fe069fe0a4d452cfd5e5d675049a41367787836cf03f5b63964b6c09218cd9f4ff0352035c1f62a04b0cba3b75ec1e12719fd033aa73b06d32829
|
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "eventq_aws"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require "irb"
|
14
|
+
IRB.start
|
data/bin/setup
ADDED
@@ -0,0 +1,116 @@
|
|
1
|
+
module EventQ
|
2
|
+
module Amazon
|
3
|
+
# Implements a general interface to raise an event
|
4
|
+
# EventQ::RabbitMq::EventQClient is the sister-class which does the same for RabbitMq
|
5
|
+
class EventQClient
|
6
|
+
|
7
|
+
def initialize(options)
|
8
|
+
|
9
|
+
if options[:client] == nil
|
10
|
+
raise ':client (QueueClient) must be specified.'.freeze
|
11
|
+
end
|
12
|
+
|
13
|
+
@client = options[:client]
|
14
|
+
|
15
|
+
@serialization_manager = EventQ::SerializationProviders::Manager.new
|
16
|
+
@signature_manager = EventQ::SignatureProviders::Manager.new
|
17
|
+
|
18
|
+
#this array is used to record known event types
|
19
|
+
@known_event_types = []
|
20
|
+
|
21
|
+
end
|
22
|
+
|
23
|
+
def registered?(event_type)
|
24
|
+
@known_event_types.include?(event_type)
|
25
|
+
end
|
26
|
+
|
27
|
+
def register_event(event_type)
|
28
|
+
if registered?(event_type)
|
29
|
+
return true
|
30
|
+
end
|
31
|
+
|
32
|
+
@client.create_topic_arn(event_type)
|
33
|
+
@known_event_types << event_type
|
34
|
+
true
|
35
|
+
end
|
36
|
+
|
37
|
+
def publish(topic:, event:, context: {})
|
38
|
+
raise_event(topic, event, context)
|
39
|
+
end
|
40
|
+
|
41
|
+
def raise_event(event_type, event, context = {})
|
42
|
+
register_event(event_type)
|
43
|
+
|
44
|
+
with_prepared_message(event_type, event, context) do |message|
|
45
|
+
|
46
|
+
response = @client.sns.publish(
|
47
|
+
topic_arn: topic_arn(event_type),
|
48
|
+
message: message,
|
49
|
+
subject: event_type
|
50
|
+
)
|
51
|
+
|
52
|
+
EventQ.logger.debug do
|
53
|
+
"[#{self.class} #raise_event] - Published to SNS with topic_arn: #{topic_arn(event_type)} | event_type: #{event_type} | Message: #{message}"
|
54
|
+
end
|
55
|
+
|
56
|
+
response
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def raise_event_in_queue(event_type, event, queue, delay, context = {})
|
61
|
+
queue_url = @client.get_queue_url(queue)
|
62
|
+
with_prepared_message(event_type, event, context) do |message|
|
63
|
+
|
64
|
+
response = @client.sqs.send_message(
|
65
|
+
queue_url: queue_url,
|
66
|
+
message_body: message,
|
67
|
+
delay_seconds: delay
|
68
|
+
)
|
69
|
+
|
70
|
+
EventQ.logger.debug do
|
71
|
+
"[#{self.class} #raise_event_in_queue] - Raised event to SQS queue: #{queue_url} | event_type: #{event_type} | Message: #{message}"
|
72
|
+
end
|
73
|
+
|
74
|
+
response
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def new_message
|
79
|
+
EventQ::QueueMessage.new
|
80
|
+
end
|
81
|
+
|
82
|
+
private
|
83
|
+
|
84
|
+
def with_prepared_message(event_type, event, context)
|
85
|
+
qm = new_message
|
86
|
+
qm.content = event
|
87
|
+
qm.type = event_type
|
88
|
+
qm.context = context
|
89
|
+
qm.content_type = event.class.to_s
|
90
|
+
|
91
|
+
if EventQ::Configuration.signature_secret != nil
|
92
|
+
provider = @signature_manager.get_provider(EventQ::Configuration.signature_provider)
|
93
|
+
qm.signature = provider.write(message: qm, secret: EventQ::Configuration.signature_secret)
|
94
|
+
end
|
95
|
+
|
96
|
+
message = serialized_message(qm)
|
97
|
+
|
98
|
+
response = yield(message)
|
99
|
+
|
100
|
+
EventQ.log(:debug, "[#{self.class}] - Raised event. Message: #{message} | Type: #{event_type}.")
|
101
|
+
|
102
|
+
response.message_id
|
103
|
+
end
|
104
|
+
|
105
|
+
def serialized_message(queue_message)
|
106
|
+
serialization_provider = @serialization_manager.get_provider(EventQ::Configuration.serialization_provider)
|
107
|
+
|
108
|
+
serialization_provider.serialize(queue_message)
|
109
|
+
end
|
110
|
+
|
111
|
+
def topic_arn(event_type)
|
112
|
+
@client.get_topic_arn(event_type)
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
module EventQ
|
2
|
+
module Amazon
|
3
|
+
class QueueClient
|
4
|
+
|
5
|
+
def initialize(options = {})
|
6
|
+
if options.has_key?(:aws_key)
|
7
|
+
Aws.config[:credentials] = Aws::Credentials.new(options[:aws_key], options[:aws_secret])
|
8
|
+
end
|
9
|
+
|
10
|
+
if !options.has_key?(:aws_account_number)
|
11
|
+
raise ':aws_account_number option must be specified.'.freeze
|
12
|
+
end
|
13
|
+
|
14
|
+
@aws_account = options[:aws_account_number]
|
15
|
+
|
16
|
+
if options.has_key?(:aws_region)
|
17
|
+
@aws_region = options[:aws_region]
|
18
|
+
Aws.config[:region] = @aws_region
|
19
|
+
else
|
20
|
+
@aws_region = Aws.config[:region]
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
# Returns the AWS SQS Client
|
25
|
+
def sqs
|
26
|
+
@sqs ||= Aws::SQS::Client.new
|
27
|
+
end
|
28
|
+
|
29
|
+
# Returns the AWS SNS Client
|
30
|
+
def sns
|
31
|
+
@sns ||= Aws::SNS::Client.new
|
32
|
+
end
|
33
|
+
|
34
|
+
def get_topic_arn(event_type)
|
35
|
+
_event_type = EventQ.create_event_type(event_type)
|
36
|
+
return "arn:aws:sns:#{@aws_region}:#{@aws_account}:#{aws_safe_name(_event_type)}"
|
37
|
+
end
|
38
|
+
|
39
|
+
def get_queue_arn(queue)
|
40
|
+
_queue_name = EventQ.create_queue_name(queue.name)
|
41
|
+
return "arn:aws:sqs:#{@aws_region}:#{@aws_account}:#{aws_safe_name(_queue_name)}"
|
42
|
+
end
|
43
|
+
|
44
|
+
def create_topic_arn(event_type)
|
45
|
+
_event_type = EventQ.create_event_type(event_type)
|
46
|
+
response = sns.create_topic(name: aws_safe_name(_event_type))
|
47
|
+
return response.topic_arn
|
48
|
+
end
|
49
|
+
|
50
|
+
# Returns the URL of the queue. The queue will be created when it does
|
51
|
+
#
|
52
|
+
# @param queue [EventQ::Queue]
|
53
|
+
def get_queue_url(queue)
|
54
|
+
_queue_name = EventQ.create_queue_name(queue.name)
|
55
|
+
response= sqs.get_queue_url(
|
56
|
+
queue_name: aws_safe_name(_queue_name),
|
57
|
+
queue_owner_aws_account_id: @aws_account,
|
58
|
+
)
|
59
|
+
return response.queue_url
|
60
|
+
end
|
61
|
+
|
62
|
+
def aws_safe_name(name)
|
63
|
+
return name[0..79].gsub(/[^a-zA-Z\d_\-]/,'')
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,98 @@
|
|
1
|
+
module EventQ
|
2
|
+
module Amazon
|
3
|
+
class QueueManager
|
4
|
+
|
5
|
+
VISIBILITY_TIMEOUT = 'VisibilityTimeout'.freeze
|
6
|
+
MESSAGE_RETENTION_PERIOD = 'MessageRetentionPeriod'.freeze
|
7
|
+
|
8
|
+
def initialize(options)
|
9
|
+
|
10
|
+
if options[:client] == nil
|
11
|
+
raise ':client (QueueClient) must be specified.'.freeze
|
12
|
+
end
|
13
|
+
|
14
|
+
@client = options[:client]
|
15
|
+
|
16
|
+
@visibility_timeout = 300 #5 minutes
|
17
|
+
if options.key?(:visibility_timeout)
|
18
|
+
@visibility_timeout = options[:visibility_timeout]
|
19
|
+
end
|
20
|
+
|
21
|
+
@message_retention_period = 1209600 #14 days (max aws value)
|
22
|
+
if options.key?(:message_retention_period)
|
23
|
+
@message_retention_period = options[:message_retention_period]
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
|
28
|
+
def get_queue(queue)
|
29
|
+
|
30
|
+
if queue_exists?(queue)
|
31
|
+
update_queue(queue)
|
32
|
+
else
|
33
|
+
create_queue(queue)
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
|
38
|
+
def create_queue(queue)
|
39
|
+
_queue_name = EventQ.create_queue_name(queue.name)
|
40
|
+
response = @client.sqs.create_queue({
|
41
|
+
queue_name: _queue_name,
|
42
|
+
attributes: {
|
43
|
+
VISIBILITY_TIMEOUT => @visibility_timeout.to_s,
|
44
|
+
MESSAGE_RETENTION_PERIOD => @message_retention_period.to_s
|
45
|
+
}
|
46
|
+
})
|
47
|
+
|
48
|
+
return response.queue_url
|
49
|
+
end
|
50
|
+
|
51
|
+
def drop_queue(queue)
|
52
|
+
|
53
|
+
q = get_queue(queue)
|
54
|
+
|
55
|
+
@client.sqs.delete_queue({ queue_url: q})
|
56
|
+
|
57
|
+
return true
|
58
|
+
|
59
|
+
end
|
60
|
+
|
61
|
+
def drop_topic(event_type)
|
62
|
+
topic_arn = @client.get_topic_arn(event_type)
|
63
|
+
@client.sns.delete_topic({ topic_arn: topic_arn})
|
64
|
+
|
65
|
+
return true
|
66
|
+
end
|
67
|
+
|
68
|
+
def topic_exists?(event_type)
|
69
|
+
topic_arn = @client.get_topic_arn(event_type)
|
70
|
+
|
71
|
+
begin
|
72
|
+
@client.sns.get_topic_attributes({ topic_arn: topic_arn })
|
73
|
+
rescue
|
74
|
+
return false
|
75
|
+
end
|
76
|
+
return true
|
77
|
+
end
|
78
|
+
|
79
|
+
def queue_exists?(queue)
|
80
|
+
_queue_name = EventQ.create_queue_name(queue.name)
|
81
|
+
return @client.sqs.list_queues({ queue_name_prefix: _queue_name }).queue_urls.length > 0
|
82
|
+
end
|
83
|
+
|
84
|
+
def update_queue(queue)
|
85
|
+
url = @client.get_queue_url(queue)
|
86
|
+
@client.sqs.set_queue_attributes({
|
87
|
+
queue_url: url, # required
|
88
|
+
attributes: {
|
89
|
+
VISIBILITY_TIMEOUT => @visibility_timeout.to_s,
|
90
|
+
MESSAGE_RETENTION_PERIOD => @message_retention_period.to_s
|
91
|
+
}
|
92
|
+
})
|
93
|
+
return url
|
94
|
+
end
|
95
|
+
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
@@ -0,0 +1,386 @@
|
|
1
|
+
module EventQ
|
2
|
+
module Amazon
|
3
|
+
class QueueWorker
|
4
|
+
include EventQ::WorkerId
|
5
|
+
|
6
|
+
APPROXIMATE_RECEIVE_COUNT = 'ApproximateReceiveCount'.freeze
|
7
|
+
MESSAGE = 'Message'.freeze
|
8
|
+
|
9
|
+
attr_accessor :is_running
|
10
|
+
|
11
|
+
def initialize
|
12
|
+
@threads = []
|
13
|
+
@forks = []
|
14
|
+
@is_running = false
|
15
|
+
|
16
|
+
@on_retry_exceeded_block = nil
|
17
|
+
@on_retry_block = nil
|
18
|
+
@on_error_block = nil
|
19
|
+
|
20
|
+
@hash_helper = HashKit::Helper.new
|
21
|
+
@serialization_provider_manager = EventQ::SerializationProviders::Manager.new
|
22
|
+
@signature_provider_manager = EventQ::SignatureProviders::Manager.new
|
23
|
+
|
24
|
+
@last_gc_flush = Time.now
|
25
|
+
@gc_flush_interval = 10
|
26
|
+
|
27
|
+
@queue_poll_wait = 10
|
28
|
+
end
|
29
|
+
|
30
|
+
def start(queue, options = {}, &block)
|
31
|
+
|
32
|
+
EventQ.logger.info("[#{self.class}] - Preparing to start listening for messages.")
|
33
|
+
|
34
|
+
configure(queue, options)
|
35
|
+
|
36
|
+
if options[:client] == nil
|
37
|
+
raise "[#{self.class}] - :client (QueueClient) must be specified."
|
38
|
+
end
|
39
|
+
|
40
|
+
raise "[#{self.class}] - Worker is already running." if running?
|
41
|
+
|
42
|
+
client = options[:client]
|
43
|
+
EventQ.logger.debug do
|
44
|
+
"[#{self.class} #start] - Listening for messages on queue: #{queue.name}, Queue Url: #{client.get_queue_url(queue)}, Queue arn: #{client.get_queue_arn(queue)}"
|
45
|
+
end
|
46
|
+
|
47
|
+
EventQ.logger.info("[#{self.class}] - Listening for messages.")
|
48
|
+
|
49
|
+
@forks = []
|
50
|
+
|
51
|
+
if @fork_count > 1
|
52
|
+
@fork_count.times do
|
53
|
+
pid = fork do
|
54
|
+
start_process(options, queue, block)
|
55
|
+
end
|
56
|
+
@forks.push(pid)
|
57
|
+
end
|
58
|
+
|
59
|
+
if options.key?(:wait) && options[:wait] == true
|
60
|
+
@forks.each { |pid| Process.wait(pid) }
|
61
|
+
end
|
62
|
+
|
63
|
+
else
|
64
|
+
start_process(options, queue, block)
|
65
|
+
end
|
66
|
+
|
67
|
+
return true
|
68
|
+
end
|
69
|
+
|
70
|
+
def start_process(options, queue, block)
|
71
|
+
|
72
|
+
%w'INT TERM'.each do |sig|
|
73
|
+
Signal.trap(sig) {
|
74
|
+
stop
|
75
|
+
exit
|
76
|
+
}
|
77
|
+
end
|
78
|
+
|
79
|
+
@is_running = true
|
80
|
+
@threads = []
|
81
|
+
|
82
|
+
#loop through each thread count
|
83
|
+
@thread_count.times do
|
84
|
+
thr = Thread.new do
|
85
|
+
|
86
|
+
client = options[:client]
|
87
|
+
manager = EventQ::Amazon::QueueManager.new({ client: client })
|
88
|
+
|
89
|
+
#begin the queue loop for this thread
|
90
|
+
while true do
|
91
|
+
|
92
|
+
#check if the worker is still allowed to run and break out of thread loop if not
|
93
|
+
if !@is_running
|
94
|
+
break
|
95
|
+
end
|
96
|
+
|
97
|
+
has_message_received = thread_process_iteration(client, manager, queue, block)
|
98
|
+
|
99
|
+
gc_flush
|
100
|
+
|
101
|
+
if !has_message_received
|
102
|
+
EventQ.logger.debug { "[#{self.class}] - No message received." }
|
103
|
+
if @sleep > 0
|
104
|
+
EventQ.logger.debug { "[#{self.class}] - Sleeping for #{@sleep} seconds" }
|
105
|
+
sleep(@sleep)
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
end
|
110
|
+
|
111
|
+
end
|
112
|
+
@threads.push(thr)
|
113
|
+
|
114
|
+
end
|
115
|
+
|
116
|
+
if options.key?(:wait) && options[:wait] == true
|
117
|
+
@threads.each { |thr| thr.join }
|
118
|
+
end
|
119
|
+
|
120
|
+
end
|
121
|
+
|
122
|
+
def gc_flush
|
123
|
+
if Time.now - last_gc_flush > @gc_flush_interval
|
124
|
+
GC.start
|
125
|
+
@last_gc_flush = Time.now
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
def last_gc_flush
|
130
|
+
@last_gc_flush
|
131
|
+
end
|
132
|
+
|
133
|
+
def thread_process_iteration(client, manager, queue, block)
|
134
|
+
#get the queue
|
135
|
+
q = manager.get_queue(queue)
|
136
|
+
|
137
|
+
received = false
|
138
|
+
|
139
|
+
begin
|
140
|
+
|
141
|
+
#request a message from the queue
|
142
|
+
response = client.sqs.receive_message({
|
143
|
+
queue_url: q,
|
144
|
+
max_number_of_messages: 1,
|
145
|
+
wait_time_seconds: @queue_poll_wait,
|
146
|
+
attribute_names: [APPROXIMATE_RECEIVE_COUNT]
|
147
|
+
})
|
148
|
+
|
149
|
+
#check that a message was received
|
150
|
+
if response.messages.length > 0
|
151
|
+
received = true
|
152
|
+
begin
|
153
|
+
tag_processing_thread
|
154
|
+
process_message(response, client, queue, q, block)
|
155
|
+
ensure
|
156
|
+
untag_processing_thread
|
157
|
+
end
|
158
|
+
|
159
|
+
end
|
160
|
+
|
161
|
+
rescue => e
|
162
|
+
EventQ.log(:error, "[#{self.class}] - An unhandled error occurred. Error: #{e} | Backtrace: #{e.backtrace}")
|
163
|
+
call_on_error_block(error: e)
|
164
|
+
end
|
165
|
+
|
166
|
+
return received
|
167
|
+
end
|
168
|
+
|
169
|
+
def call_on_error_block(error:, message: nil)
|
170
|
+
if @on_error_block
|
171
|
+
EventQ.logger.debug { "[#{self.class}] - Executing on_error block." }
|
172
|
+
begin
|
173
|
+
@on_error_block.call(error, message)
|
174
|
+
rescue => e
|
175
|
+
EventQ.logger.error("[#{self.class}] - An error occurred executing the on_error block. Error: #{e}")
|
176
|
+
end
|
177
|
+
else
|
178
|
+
EventQ.logger.debug { "[#{self.class}] - No on_error block specified to execute." }
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
def call_on_retry_exceeded_block(message)
|
183
|
+
if @on_retry_exceeded_block != nil
|
184
|
+
EventQ.logger.debug { "[#{self.class}] - Executing on_retry_exceeded block." }
|
185
|
+
begin
|
186
|
+
@on_retry_exceeded_block.call(message)
|
187
|
+
rescue => e
|
188
|
+
EventQ.logger.error("[#{self.class}] - An error occurred executing the on_retry_exceeded block. Error: #{e}")
|
189
|
+
end
|
190
|
+
else
|
191
|
+
EventQ.logger.debug { "[#{self.class}] - No on_retry_exceeded block specified." }
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
def call_on_retry_block(message)
|
196
|
+
if @on_retry_block
|
197
|
+
EventQ.logger.debug { "[#{self.class}] - Executing on_retry block." }
|
198
|
+
begin
|
199
|
+
@on_retry_block.call(message, abort)
|
200
|
+
rescue => e
|
201
|
+
EventQ.logger.error("[#{self.class}] - An error occurred executing the on_retry block. Error: #{e}")
|
202
|
+
end
|
203
|
+
else
|
204
|
+
EventQ.logger.debug { "[#{self.class}] - No on_retry block specified." }
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
def stop
|
209
|
+
EventQ.logger.info("[#{self.class}] - Stopping.")
|
210
|
+
@is_running = false
|
211
|
+
@threads.each { |thr| thr.join }
|
212
|
+
return true
|
213
|
+
end
|
214
|
+
|
215
|
+
def on_retry_exceeded(&block)
|
216
|
+
@retry_exceeded_block = block
|
217
|
+
end
|
218
|
+
|
219
|
+
def on_retry(&block)
|
220
|
+
@on_retry_block = block
|
221
|
+
return nil
|
222
|
+
end
|
223
|
+
|
224
|
+
def on_error(&block)
|
225
|
+
@on_error_block = block
|
226
|
+
return nil
|
227
|
+
end
|
228
|
+
|
229
|
+
def running?
|
230
|
+
return @is_running
|
231
|
+
end
|
232
|
+
|
233
|
+
def deserialize_message(payload)
|
234
|
+
provider = @serialization_provider_manager.get_provider(EventQ::Configuration.serialization_provider)
|
235
|
+
return provider.deserialize(payload)
|
236
|
+
end
|
237
|
+
|
238
|
+
def serialize_message(msg)
|
239
|
+
provider = @serialization_provider_manager.get_provider(EventQ::Configuration.serialization_provider)
|
240
|
+
return provider.serialize(msg)
|
241
|
+
end
|
242
|
+
|
243
|
+
private
|
244
|
+
|
245
|
+
def process_message(response, client, queue, q, block)
|
246
|
+
msg = response.messages[0]
|
247
|
+
retry_attempts = msg.attributes[APPROXIMATE_RECEIVE_COUNT].to_i - 1
|
248
|
+
|
249
|
+
#deserialize the message payload
|
250
|
+
payload = JSON.load(msg.body)
|
251
|
+
message = deserialize_message(payload[MESSAGE])
|
252
|
+
|
253
|
+
message_args = EventQ::MessageArgs.new(type: message.type,
|
254
|
+
retry_attempts: retry_attempts,
|
255
|
+
context: message.context,
|
256
|
+
content_type: message.content_type)
|
257
|
+
|
258
|
+
EventQ.logger.info("[#{self.class}] - Message received. Retry Attempts: #{retry_attempts}")
|
259
|
+
|
260
|
+
@signature_provider_manager.validate_signature(message: message, queue: queue)
|
261
|
+
|
262
|
+
if(!EventQ::NonceManager.is_allowed?(message.id))
|
263
|
+
EventQ.logger.info("[#{self.class}] - Duplicate Message received. Dropping message.")
|
264
|
+
client.sqs.delete_message({ queue_url: q, receipt_handle: msg.receipt_handle })
|
265
|
+
return false
|
266
|
+
end
|
267
|
+
|
268
|
+
#begin worker block for queue message
|
269
|
+
begin
|
270
|
+
|
271
|
+
block.call(message.content, message_args)
|
272
|
+
|
273
|
+
if message_args.abort == true
|
274
|
+
EventQ.logger.info("[#{self.class}] - Message aborted.")
|
275
|
+
else
|
276
|
+
#accept the message as processed
|
277
|
+
client.sqs.delete_message({ queue_url: q, receipt_handle: msg.receipt_handle })
|
278
|
+
EventQ.logger.info("[#{self.class}] - Message acknowledged.")
|
279
|
+
end
|
280
|
+
|
281
|
+
rescue => e
|
282
|
+
EventQ.logger.error("[#{self.class}] - An unhandled error happened while attempting to process a queue message. Error: #{e} | Backtrace: #{e.backtrace}")
|
283
|
+
error = true
|
284
|
+
call_on_error_block(error: e, message: message)
|
285
|
+
end
|
286
|
+
|
287
|
+
if message_args.abort || error
|
288
|
+
EventQ::NonceManager.failed(message.id)
|
289
|
+
reject_message(queue, client, msg, q, retry_attempts, message, message_args.abort)
|
290
|
+
else
|
291
|
+
EventQ::NonceManager.complete(message.id)
|
292
|
+
end
|
293
|
+
|
294
|
+
return true
|
295
|
+
end
|
296
|
+
|
297
|
+
def reject_message(queue, client, msg, q, retry_attempts, message, abort)
|
298
|
+
|
299
|
+
if !queue.allow_retry || retry_attempts >= queue.max_retry_attempts
|
300
|
+
|
301
|
+
EventQ.logger.info("[#{self.class}] - Message rejected removing from queue. Message: #{serialize_message(message)}")
|
302
|
+
|
303
|
+
#remove the message from the queue so that it does not get retried again
|
304
|
+
client.sqs.delete_message({ queue_url: q, receipt_handle: msg.receipt_handle })
|
305
|
+
|
306
|
+
if retry_attempts >= queue.max_retry_attempts
|
307
|
+
|
308
|
+
EventQ.logger.info("[#{self.class}] - Message retry attempt limit exceeded.")
|
309
|
+
call_on_retry_exceeded_block(message)
|
310
|
+
|
311
|
+
end
|
312
|
+
|
313
|
+
elsif queue.allow_retry
|
314
|
+
|
315
|
+
retry_attempts += 1
|
316
|
+
|
317
|
+
EventQ.logger.info("[#{self.class}] - Message rejected requesting retry. Attempts: #{retry_attempts}")
|
318
|
+
|
319
|
+
if queue.allow_retry_back_off == true
|
320
|
+
EventQ.logger.debug { "[#{self.class}] - Calculating message back off retry delay. Attempts: #{retry_attempts} * Delay: #{queue.retry_delay}" }
|
321
|
+
visibility_timeout = (queue.retry_delay * retry_attempts) / 1000
|
322
|
+
if visibility_timeout > (queue.max_retry_delay / 1000)
|
323
|
+
EventQ.logger.debug { "[#{self.class}] - Max message back off retry delay reached." }
|
324
|
+
visibility_timeout = queue.max_retry_delay / 1000
|
325
|
+
end
|
326
|
+
else
|
327
|
+
EventQ.logger.debug { "[#{self.class}] - Setting fixed retry delay for message." }
|
328
|
+
visibility_timeout = queue.retry_delay / 1000
|
329
|
+
end
|
330
|
+
|
331
|
+
if visibility_timeout > 43200
|
332
|
+
EventQ.logger.debug { "[#{self.class}] - AWS max visibility timeout of 12 hours has been exceeded. Setting message retry delay to 12 hours." }
|
333
|
+
visibility_timeout = 43200
|
334
|
+
end
|
335
|
+
|
336
|
+
EventQ.logger.debug { "[#{self.class}] - Sending message for retry. Message TTL: #{visibility_timeout}" }
|
337
|
+
client.sqs.change_message_visibility({
|
338
|
+
queue_url: q, # required
|
339
|
+
receipt_handle: msg.receipt_handle, # required
|
340
|
+
visibility_timeout: visibility_timeout.to_s, # required
|
341
|
+
})
|
342
|
+
|
343
|
+
call_on_retry_block(message)
|
344
|
+
|
345
|
+
end
|
346
|
+
|
347
|
+
end
|
348
|
+
|
349
|
+
def configure(queue, options = {})
|
350
|
+
|
351
|
+
@queue = queue
|
352
|
+
|
353
|
+
#default thread count
|
354
|
+
@thread_count = 5
|
355
|
+
if options.key?(:thread_count)
|
356
|
+
@thread_count = options[:thread_count]
|
357
|
+
end
|
358
|
+
|
359
|
+
#default sleep time in seconds
|
360
|
+
@sleep = 5
|
361
|
+
if options.key?(:sleep)
|
362
|
+
@sleep = options[:sleep]
|
363
|
+
end
|
364
|
+
|
365
|
+
@fork_count = 1
|
366
|
+
if options.key?(:fork_count)
|
367
|
+
@fork_count = options[:fork_count]
|
368
|
+
end
|
369
|
+
|
370
|
+
if options.key?(:gc_flush_interval)
|
371
|
+
@gc_flush_interval = options[:gc_flush_interval]
|
372
|
+
end
|
373
|
+
|
374
|
+
if options.key?(:queue_poll_wait)
|
375
|
+
@queue_poll_wait = options[:queue_poll_wait]
|
376
|
+
end
|
377
|
+
|
378
|
+
EventQ.logger.info("[#{self.class}] - Configuring. Process Count: #{@fork_count} | Thread Count: #{@thread_count} | Interval Sleep: #{@sleep} | GC Flush Interval: #{@gc_flush_interval} | Queue Poll Wait: #{@queue_poll_wait}.")
|
379
|
+
|
380
|
+
return true
|
381
|
+
|
382
|
+
end
|
383
|
+
|
384
|
+
end
|
385
|
+
end
|
386
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module EventQ
|
2
|
+
module Amazon
|
3
|
+
class StatusChecker
|
4
|
+
|
5
|
+
def initialize(queue_manager:, client:)
|
6
|
+
|
7
|
+
if queue_manager == nil
|
8
|
+
raise 'queue_manager must be specified.'.freeze
|
9
|
+
end
|
10
|
+
|
11
|
+
@queue_manager = queue_manager
|
12
|
+
|
13
|
+
end
|
14
|
+
|
15
|
+
def queue?(queue)
|
16
|
+
@queue_manager.queue_exists?(queue)
|
17
|
+
end
|
18
|
+
|
19
|
+
def event_type?(event_type)
|
20
|
+
@queue_manager.topic_exists?(event_type)
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
module EventQ
|
2
|
+
module Amazon
|
3
|
+
class SubscriptionManager
|
4
|
+
|
5
|
+
def initialize(options)
|
6
|
+
|
7
|
+
if options[:client] == nil
|
8
|
+
raise "[#{self.class}] - :client (QueueClient) must be specified."
|
9
|
+
end
|
10
|
+
|
11
|
+
@client = options[:client]
|
12
|
+
|
13
|
+
if options[:queue_manager] == nil
|
14
|
+
raise "[#{self.class}] - :queue_manager (QueueManager) must be specified."
|
15
|
+
end
|
16
|
+
|
17
|
+
@manager = options[:queue_manager]
|
18
|
+
end
|
19
|
+
|
20
|
+
def subscribe(event_type, queue)
|
21
|
+
|
22
|
+
topic_arn = @client.create_topic_arn(event_type)
|
23
|
+
|
24
|
+
q = @manager.get_queue(queue)
|
25
|
+
queue_arn = @client.get_queue_arn(queue)
|
26
|
+
|
27
|
+
@client.sqs.set_queue_attributes({
|
28
|
+
queue_url: q,
|
29
|
+
attributes:{
|
30
|
+
'Policy'.freeze => '{
|
31
|
+
"Version": "2012-10-17",
|
32
|
+
"Id": "SNStoSQS",
|
33
|
+
"Statement": [
|
34
|
+
{
|
35
|
+
"Sid":"rule1",
|
36
|
+
"Effect": "Allow",
|
37
|
+
"Principal": "*",
|
38
|
+
"Action": "sqs:*",
|
39
|
+
"Resource": "' + queue_arn + '"
|
40
|
+
}
|
41
|
+
]
|
42
|
+
}'
|
43
|
+
}
|
44
|
+
})
|
45
|
+
|
46
|
+
@client.sns.subscribe({
|
47
|
+
topic_arn: topic_arn,
|
48
|
+
protocol: 'sqs'.freeze,
|
49
|
+
endpoint: queue_arn
|
50
|
+
})
|
51
|
+
EventQ.logger.debug do
|
52
|
+
"[#{self.class} #subscribe] - Subscribing Queue: #{queue.name} to topic_arn: #{topic_arn}, endpoint: #{queue_arn}"
|
53
|
+
end
|
54
|
+
return true
|
55
|
+
|
56
|
+
end
|
57
|
+
|
58
|
+
def unsubscribe(queue)
|
59
|
+
|
60
|
+
raise "[#{self.class}] - Not implemented. Please unsubscribe the queue from the topic inside the AWS Management Console."
|
61
|
+
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,370 @@
|
|
1
|
+
require 'java'
|
2
|
+
java_import java.util.concurrent.Executors
|
3
|
+
module EventQ
|
4
|
+
module Amazon
|
5
|
+
class QueueWorker
|
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
|
+
@is_running = false
|
15
|
+
|
16
|
+
@on_retry_exceeded_block = nil
|
17
|
+
@on_retry_block = nil
|
18
|
+
@on_error_block = nil
|
19
|
+
|
20
|
+
@hash_helper = HashKit::Helper.new
|
21
|
+
@serialization_provider_manager = EventQ::SerializationProviders::Manager.new
|
22
|
+
@signature_provider_manager = EventQ::SignatureProviders::Manager.new
|
23
|
+
|
24
|
+
@last_gc_flush = Time.now
|
25
|
+
@gc_flush_interval = 10
|
26
|
+
|
27
|
+
@queue_poll_wait = 10
|
28
|
+
end
|
29
|
+
|
30
|
+
def start(queue, options = {}, &block)
|
31
|
+
|
32
|
+
EventQ.logger.info("[#{self.class}] - Preparing to start listening for messages.")
|
33
|
+
|
34
|
+
configure(queue, options)
|
35
|
+
|
36
|
+
if options[:client] == nil
|
37
|
+
raise "[#{self.class}] - :client (QueueClient) must be specified."
|
38
|
+
end
|
39
|
+
|
40
|
+
raise "[#{self.class}] - Worker is already running." if running?
|
41
|
+
|
42
|
+
client = options[:client]
|
43
|
+
EventQ.logger.debug do
|
44
|
+
"[#{self.class} #start] - Listening for messages on queue: #{queue.name}, Queue Url: #{client.get_queue_url(queue)}, Queue arn: #{client.get_queue_arn(queue)}"
|
45
|
+
end
|
46
|
+
|
47
|
+
EventQ.logger.info("[#{self.class}] - Listening for messages.")
|
48
|
+
|
49
|
+
start_process(options, queue, block)
|
50
|
+
|
51
|
+
return true
|
52
|
+
end
|
53
|
+
|
54
|
+
def start_process(options, queue, block)
|
55
|
+
|
56
|
+
%w'INT TERM'.each do |sig|
|
57
|
+
Signal.trap(sig) {
|
58
|
+
stop
|
59
|
+
exit
|
60
|
+
}
|
61
|
+
end
|
62
|
+
|
63
|
+
@is_running = true
|
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
|
+
client = options[:client]
|
73
|
+
manager = EventQ::Amazon::QueueManager.new({ client: client })
|
74
|
+
|
75
|
+
#begin the queue loop for this thread
|
76
|
+
while true do
|
77
|
+
|
78
|
+
#check if the worker is still allowed to run and break out of thread loop if not
|
79
|
+
unless running?
|
80
|
+
break
|
81
|
+
end
|
82
|
+
|
83
|
+
if @executor.is_shutdown
|
84
|
+
break
|
85
|
+
end
|
86
|
+
|
87
|
+
has_message_received = thread_process_iteration(client, manager, queue, block)
|
88
|
+
|
89
|
+
gc_flush
|
90
|
+
|
91
|
+
if !has_message_received
|
92
|
+
EventQ.logger.debug { "[#{self.class}] - No message received." }
|
93
|
+
if @sleep > 0
|
94
|
+
EventQ.logger.debug { "[#{self.class}] - Sleeping for #{@sleep} seconds" }
|
95
|
+
sleep(@sleep)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
end
|
100
|
+
|
101
|
+
end
|
102
|
+
|
103
|
+
end
|
104
|
+
|
105
|
+
if options.key?(:wait) && options[:wait] == true
|
106
|
+
while running? do end
|
107
|
+
end
|
108
|
+
|
109
|
+
end
|
110
|
+
|
111
|
+
def gc_flush
|
112
|
+
if Time.now - last_gc_flush > @gc_flush_interval
|
113
|
+
GC.start
|
114
|
+
@last_gc_flush = Time.now
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
def last_gc_flush
|
119
|
+
@last_gc_flush
|
120
|
+
end
|
121
|
+
|
122
|
+
def thread_process_iteration(client, manager, queue, block)
|
123
|
+
#get the queue
|
124
|
+
q = manager.get_queue(queue)
|
125
|
+
|
126
|
+
received = false
|
127
|
+
|
128
|
+
begin
|
129
|
+
|
130
|
+
#request a message from the queue
|
131
|
+
response = client.sqs.receive_message({
|
132
|
+
queue_url: q,
|
133
|
+
max_number_of_messages: 1,
|
134
|
+
wait_time_seconds: @queue_poll_wait,
|
135
|
+
attribute_names: [APPROXIMATE_RECEIVE_COUNT]
|
136
|
+
})
|
137
|
+
|
138
|
+
#check that a message was received
|
139
|
+
if response.messages.length > 0
|
140
|
+
received = true
|
141
|
+
begin
|
142
|
+
tag_processing_thread
|
143
|
+
process_message(response, client, queue, q, block)
|
144
|
+
ensure
|
145
|
+
untag_processing_thread
|
146
|
+
end
|
147
|
+
|
148
|
+
end
|
149
|
+
|
150
|
+
rescue => e
|
151
|
+
EventQ.log(:error, "[#{self.class}] - An unhandled error occurred. Error: #{e} | Backtrace: #{e.backtrace}")
|
152
|
+
call_on_error_block(error: e)
|
153
|
+
end
|
154
|
+
|
155
|
+
return received
|
156
|
+
end
|
157
|
+
|
158
|
+
def call_on_error_block(error:, message: nil)
|
159
|
+
if @on_error_block
|
160
|
+
EventQ.logger.debug { "[#{self.class}] - Executing on_error block." }
|
161
|
+
begin
|
162
|
+
@on_error_block.call(error, message)
|
163
|
+
rescue => e
|
164
|
+
EventQ.logger.error("[#{self.class}] - An error occurred executing the on_error block. Error: #{e}")
|
165
|
+
end
|
166
|
+
else
|
167
|
+
EventQ.logger.debug { "[#{self.class}] - No on_error block specified to execute." }
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
def call_on_retry_exceeded_block(message)
|
172
|
+
if @on_retry_exceeded_block != nil
|
173
|
+
EventQ.logger.debug { "[#{self.class}] - Executing on_retry_exceeded block." }
|
174
|
+
begin
|
175
|
+
@on_retry_exceeded_block.call(message)
|
176
|
+
rescue => e
|
177
|
+
EventQ.logger.error("[#{self.class}] - An error occurred executing the on_retry_exceeded block. Error: #{e}")
|
178
|
+
end
|
179
|
+
else
|
180
|
+
EventQ.logger.debug { "[#{self.class}] - No on_retry_exceeded block specified." }
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
def call_on_retry_block(message)
|
185
|
+
if @on_retry_block
|
186
|
+
EventQ.logger.debug { "[#{self.class}] - Executing on_retry block." }
|
187
|
+
begin
|
188
|
+
@on_retry_block.call(message, abort)
|
189
|
+
rescue => e
|
190
|
+
EventQ.logger.error("[#{self.class}] - An error occurred executing the on_retry block. Error: #{e}")
|
191
|
+
end
|
192
|
+
else
|
193
|
+
EventQ.logger.debug { "[#{self.class}] - No on_retry block specified." }
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
def stop
|
198
|
+
EventQ.logger.info("[#{self.class}] - Stopping.")
|
199
|
+
@is_running = false
|
200
|
+
@executor.shutdown
|
201
|
+
return true
|
202
|
+
end
|
203
|
+
|
204
|
+
def on_retry_exceeded(&block)
|
205
|
+
@retry_exceeded_block = block
|
206
|
+
end
|
207
|
+
|
208
|
+
def on_retry(&block)
|
209
|
+
@on_retry_block = block
|
210
|
+
return nil
|
211
|
+
end
|
212
|
+
|
213
|
+
def on_error(&block)
|
214
|
+
@on_error_block = block
|
215
|
+
return nil
|
216
|
+
end
|
217
|
+
|
218
|
+
def running?
|
219
|
+
return @is_running
|
220
|
+
end
|
221
|
+
|
222
|
+
def deserialize_message(payload)
|
223
|
+
provider = @serialization_provider_manager.get_provider(EventQ::Configuration.serialization_provider)
|
224
|
+
return provider.deserialize(payload)
|
225
|
+
end
|
226
|
+
|
227
|
+
def serialize_message(msg)
|
228
|
+
provider = @serialization_provider_manager.get_provider(EventQ::Configuration.serialization_provider)
|
229
|
+
return provider.serialize(msg)
|
230
|
+
end
|
231
|
+
|
232
|
+
private
|
233
|
+
|
234
|
+
def process_message(response, client, queue, q, block)
|
235
|
+
msg = response.messages[0]
|
236
|
+
retry_attempts = msg.attributes[APPROXIMATE_RECEIVE_COUNT].to_i - 1
|
237
|
+
|
238
|
+
#deserialize the message payload
|
239
|
+
payload = JSON.load(msg.body)
|
240
|
+
message = deserialize_message(payload[MESSAGE])
|
241
|
+
|
242
|
+
message_args = EventQ::MessageArgs.new(type: message.type,
|
243
|
+
retry_attempts: retry_attempts,
|
244
|
+
context: message.context,
|
245
|
+
content_type: message.content_type)
|
246
|
+
|
247
|
+
EventQ.logger.info("[#{self.class}] - Message received. Retry Attempts: #{retry_attempts}")
|
248
|
+
|
249
|
+
@signature_provider_manager.validate_signature(message: message, queue: queue)
|
250
|
+
|
251
|
+
if(!EventQ::NonceManager.is_allowed?(message.id))
|
252
|
+
EventQ.logger.info("[#{self.class}] - Duplicate Message received. Dropping message.")
|
253
|
+
client.sqs.delete_message({ queue_url: q, receipt_handle: msg.receipt_handle })
|
254
|
+
return false
|
255
|
+
end
|
256
|
+
|
257
|
+
#begin worker block for queue message
|
258
|
+
begin
|
259
|
+
|
260
|
+
block.call(message.content, message_args)
|
261
|
+
|
262
|
+
if message_args.abort == true
|
263
|
+
EventQ.logger.info("[#{self.class}] - Message aborted.")
|
264
|
+
else
|
265
|
+
#accept the message as processed
|
266
|
+
client.sqs.delete_message({ queue_url: q, receipt_handle: msg.receipt_handle })
|
267
|
+
EventQ.logger.info("[#{self.class}] - Message acknowledged.")
|
268
|
+
end
|
269
|
+
|
270
|
+
rescue => e
|
271
|
+
EventQ.logger.error("[#{self.class}] - An unhandled error happened while attempting to process a queue message. Error: #{e} | Backtrace: #{e.backtrace}")
|
272
|
+
error = true
|
273
|
+
call_on_error_block(error: e, message: message)
|
274
|
+
end
|
275
|
+
|
276
|
+
if message_args.abort || error
|
277
|
+
EventQ::NonceManager.failed(message.id)
|
278
|
+
reject_message(queue, client, msg, q, retry_attempts, message, message_args.abort)
|
279
|
+
else
|
280
|
+
EventQ::NonceManager.complete(message.id)
|
281
|
+
end
|
282
|
+
|
283
|
+
return true
|
284
|
+
end
|
285
|
+
|
286
|
+
def reject_message(queue, client, msg, q, retry_attempts, message, abort)
|
287
|
+
|
288
|
+
if !queue.allow_retry || retry_attempts >= queue.max_retry_attempts
|
289
|
+
|
290
|
+
EventQ.logger.info("[#{self.class}] - Message rejected removing from queue. Message: #{serialize_message(message)}")
|
291
|
+
|
292
|
+
#remove the message from the queue so that it does not get retried again
|
293
|
+
client.sqs.delete_message({ queue_url: q, receipt_handle: msg.receipt_handle })
|
294
|
+
|
295
|
+
if retry_attempts >= queue.max_retry_attempts
|
296
|
+
|
297
|
+
EventQ.logger.info("[#{self.class}] - Message retry attempt limit exceeded.")
|
298
|
+
call_on_retry_exceeded_block(message)
|
299
|
+
|
300
|
+
end
|
301
|
+
|
302
|
+
elsif queue.allow_retry
|
303
|
+
|
304
|
+
retry_attempts += 1
|
305
|
+
|
306
|
+
EventQ.logger.info("[#{self.class}] - Message rejected requesting retry. Attempts: #{retry_attempts}")
|
307
|
+
|
308
|
+
if queue.allow_retry_back_off == true
|
309
|
+
EventQ.logger.debug { "[#{self.class}] - Calculating message back off retry delay. Attempts: #{retry_attempts} * Delay: #{queue.retry_delay}" }
|
310
|
+
visibility_timeout = (queue.retry_delay * retry_attempts) / 1000
|
311
|
+
if visibility_timeout > (queue.max_retry_delay / 1000)
|
312
|
+
EventQ.logger.debug { "[#{self.class}] - Max message back off retry delay reached." }
|
313
|
+
visibility_timeout = queue.max_retry_delay / 1000
|
314
|
+
end
|
315
|
+
else
|
316
|
+
EventQ.logger.debug { "[#{self.class}] - Setting fixed retry delay for message." }
|
317
|
+
visibility_timeout = queue.retry_delay / 1000
|
318
|
+
end
|
319
|
+
|
320
|
+
if visibility_timeout > 43200
|
321
|
+
EventQ.logger.debug { "[#{self.class}] - AWS max visibility timeout of 12 hours has been exceeded. Setting message retry delay to 12 hours." }
|
322
|
+
visibility_timeout = 43200
|
323
|
+
end
|
324
|
+
|
325
|
+
EventQ.logger.debug { "[#{self.class}] - Sending message for retry. Message TTL: #{visibility_timeout}" }
|
326
|
+
client.sqs.change_message_visibility({
|
327
|
+
queue_url: q, # required
|
328
|
+
receipt_handle: msg.receipt_handle, # required
|
329
|
+
visibility_timeout: visibility_timeout.to_s, # required
|
330
|
+
})
|
331
|
+
|
332
|
+
call_on_retry_block(message)
|
333
|
+
|
334
|
+
end
|
335
|
+
|
336
|
+
end
|
337
|
+
|
338
|
+
def configure(queue, options = {})
|
339
|
+
|
340
|
+
@queue = queue
|
341
|
+
|
342
|
+
#default thread count
|
343
|
+
@thread_count = 5
|
344
|
+
if options.key?(:thread_count)
|
345
|
+
@thread_count = options[:thread_count]
|
346
|
+
end
|
347
|
+
|
348
|
+
#default sleep time in seconds
|
349
|
+
@sleep = 5
|
350
|
+
if options.key?(:sleep)
|
351
|
+
@sleep = options[:sleep]
|
352
|
+
end
|
353
|
+
|
354
|
+
if options.key?(:gc_flush_interval)
|
355
|
+
@gc_flush_interval = options[:gc_flush_interval]
|
356
|
+
end
|
357
|
+
|
358
|
+
if options.key?(:queue_poll_wait)
|
359
|
+
@queue_poll_wait = options[:queue_poll_wait]
|
360
|
+
end
|
361
|
+
|
362
|
+
EventQ.logger.info("[#{self.class}] - Configuring. Thread Count: #{@thread_count} | Interval Sleep: #{@sleep} | GC Flush Interval: #{@gc_flush_interval} | Queue Poll Wait: #{@queue_poll_wait}.")
|
363
|
+
|
364
|
+
return true
|
365
|
+
|
366
|
+
end
|
367
|
+
|
368
|
+
end
|
369
|
+
end
|
370
|
+
end
|
data/lib/eventq_aws.rb
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'aws-sdk-core'
|
2
|
+
require 'eventq_base'
|
3
|
+
|
4
|
+
require 'eventq_aws/version'
|
5
|
+
require 'eventq_aws/aws_eventq_client'
|
6
|
+
require 'eventq_aws/aws_queue_client'
|
7
|
+
require 'eventq_aws/aws_queue_manager'
|
8
|
+
require 'eventq_aws/aws_subscription_manager'
|
9
|
+
require_relative 'eventq_aws/aws_status_checker'
|
10
|
+
|
11
|
+
if RUBY_PLATFORM =~ /java/
|
12
|
+
require 'eventq_aws/jruby/aws_queue_worker'
|
13
|
+
else
|
14
|
+
require 'eventq_aws/aws_queue_worker'
|
15
|
+
end
|
16
|
+
|
17
|
+
module EventQ
|
18
|
+
def self.namespace
|
19
|
+
@namespace
|
20
|
+
end
|
21
|
+
def self.namespace=(value)
|
22
|
+
@namespace = value
|
23
|
+
end
|
24
|
+
def self.create_event_type(event_type)
|
25
|
+
if EventQ.namespace == nil
|
26
|
+
return event_type
|
27
|
+
end
|
28
|
+
return "#{EventQ.namespace}-#{event_type}"
|
29
|
+
end
|
30
|
+
def self.create_queue_name(queue_name)
|
31
|
+
if EventQ.namespace == nil
|
32
|
+
return queue_name
|
33
|
+
end
|
34
|
+
return "#{EventQ.namespace}-#{queue_name}"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
metadata
ADDED
@@ -0,0 +1,125 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: eventq_aws
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.14.0
|
5
|
+
platform: java
|
6
|
+
authors:
|
7
|
+
- vaughanbrittonsage
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2017-06-27 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
15
|
+
requirements:
|
16
|
+
- - "~>"
|
17
|
+
- !ruby/object:Gem::Version
|
18
|
+
version: '1.11'
|
19
|
+
name: bundler
|
20
|
+
prerelease: false
|
21
|
+
type: :development
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.11'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
requirement: !ruby/object:Gem::Requirement
|
29
|
+
requirements:
|
30
|
+
- - "~>"
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '10.0'
|
33
|
+
name: rake
|
34
|
+
prerelease: false
|
35
|
+
type: :development
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '10.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
requirement: !ruby/object:Gem::Requirement
|
43
|
+
requirements:
|
44
|
+
- - ">="
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '0'
|
47
|
+
name: rspec
|
48
|
+
prerelease: false
|
49
|
+
type: :development
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
requirement: !ruby/object:Gem::Requirement
|
57
|
+
requirements:
|
58
|
+
- - ">="
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: '0'
|
61
|
+
name: aws-sdk-core
|
62
|
+
prerelease: false
|
63
|
+
type: :runtime
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
requirement: !ruby/object:Gem::Requirement
|
71
|
+
requirements:
|
72
|
+
- - "~>"
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
version: '1.15'
|
75
|
+
name: eventq_base
|
76
|
+
prerelease: false
|
77
|
+
type: :runtime
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '1.15'
|
83
|
+
description: This is the aws implementation for EventQ
|
84
|
+
email:
|
85
|
+
- vaughanbritton@gmail.com
|
86
|
+
executables: []
|
87
|
+
extensions: []
|
88
|
+
extra_rdoc_files: []
|
89
|
+
files:
|
90
|
+
- bin/console
|
91
|
+
- bin/setup
|
92
|
+
- lib/eventq_aws.rb
|
93
|
+
- lib/eventq_aws/aws_eventq_client.rb
|
94
|
+
- lib/eventq_aws/aws_queue_client.rb
|
95
|
+
- lib/eventq_aws/aws_queue_manager.rb
|
96
|
+
- lib/eventq_aws/aws_queue_worker.rb
|
97
|
+
- lib/eventq_aws/aws_status_checker.rb
|
98
|
+
- lib/eventq_aws/aws_subscription_manager.rb
|
99
|
+
- lib/eventq_aws/jruby/aws_queue_worker.rb
|
100
|
+
- lib/eventq_aws/version.rb
|
101
|
+
homepage: https://github.com/vaughanbrittonsage/eventq
|
102
|
+
licenses:
|
103
|
+
- MIT
|
104
|
+
metadata: {}
|
105
|
+
post_install_message:
|
106
|
+
rdoc_options: []
|
107
|
+
require_paths:
|
108
|
+
- lib
|
109
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
110
|
+
requirements:
|
111
|
+
- - ">="
|
112
|
+
- !ruby/object:Gem::Version
|
113
|
+
version: '0'
|
114
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
115
|
+
requirements:
|
116
|
+
- - ">="
|
117
|
+
- !ruby/object:Gem::Version
|
118
|
+
version: '0'
|
119
|
+
requirements: []
|
120
|
+
rubyforge_project:
|
121
|
+
rubygems_version: 2.6.11
|
122
|
+
signing_key:
|
123
|
+
specification_version: 4
|
124
|
+
summary: This is the aws implementation for EventQ
|
125
|
+
test_files: []
|