eventq_aws 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 72dc6e5eedbb1a486df5fb6ae630c9ada26a08b5
4
+ data.tar.gz: 953364700ea24b683038d3fbd4b2dd5dffbfa7bd
5
+ SHA512:
6
+ metadata.gz: 66b70231f26a2723ff5a37104991d90d562ae6c97e52619472e174aff95e49b53a5f3362bb97718668fc8e2c070746dde9a9426a1086fb784176dfeb87518814
7
+ data.tar.gz: 0633ab90abfc5d3accfd9803ce68967f10ce5de746ef29fa40b49335e7bd73805c7790c32d1e0f9707872f930e7138a0c512ad7e6b4caf3e9ffbd5633b6b3f0c
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,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,28 @@
1
+ require 'oj'
2
+
3
+ class AwsEventQClient
4
+ def initialize
5
+ @client = AwsQueueClient.new
6
+ end
7
+
8
+ def raise(event_type, event)
9
+
10
+ topic_arn = @client.get_topic_arn(event_type)
11
+
12
+ qm = QueueMessage.new
13
+ qm.content = event
14
+ qm.type = event_type
15
+
16
+ message = Oj.dump(qm)
17
+
18
+ response = @client.sns.publish({
19
+ topic_arn: topic_arn,
20
+ message: message,
21
+ subject: event_type
22
+ })
23
+
24
+ return response.message_id
25
+
26
+ end
27
+
28
+ end
@@ -0,0 +1,28 @@
1
+ class AwsQueueClient
2
+
3
+ attr_reader :sns
4
+ attr_reader :sqs
5
+
6
+ def initialize
7
+
8
+ Aws.config[:credentials] = Aws::Credentials.new(ENV['AWS_KEY'], ENV['AWS_SECRET'])
9
+ Aws.config[:region] = ENV['AWS_REGION'] || 'us-west-2'
10
+
11
+ @sns = Aws::SNS::Client.new
12
+ @sqs = Aws::SQS::Client.new
13
+
14
+ @aws_account = ENV['AWS_ACCOUNT_NUMBER']
15
+ @aws_region = ENV['AWS_REGION'] || 'us-west-2'
16
+
17
+ end
18
+
19
+ def get_topic_arn(event_type)
20
+ response = @sns.create_topic({ name: event_type })
21
+ return response.topic_arn
22
+ end
23
+
24
+ def get_queue_arn(queue)
25
+ return "arn:aws:sqs:#{@aws_region}:#{@aws_account}:#{queue.name}"
26
+ end
27
+
28
+ end
@@ -0,0 +1,35 @@
1
+ class AwsQueueManager
2
+
3
+ @@dead_letter_queue = 'dead_letter_archive'
4
+
5
+ def initialize
6
+ @client = AwsQueueClient.new
7
+ end
8
+
9
+ def get_queue(queue)
10
+
11
+ response = @client.sqs.create_queue({
12
+ queue_name: queue.name,
13
+ attributes: {
14
+ 'VisibilityTimeout' => (queue.retry_delay / 1000).to_s
15
+ }
16
+ })
17
+
18
+ return response.queue_url
19
+
20
+ end
21
+
22
+ def drop_queue(queue)
23
+
24
+ q = get_queue(queue)
25
+
26
+ @client.sqs.delete_queue({ queue_url: q})
27
+
28
+ end
29
+
30
+ def drop_topic(event_type)
31
+ topic_arn = @client.get_topic_arn(event_type)
32
+ @client.sns.delete_topic({ topic_arn: topic_arn})
33
+ end
34
+
35
+ end
@@ -0,0 +1,145 @@
1
+ class AwsQueueWorker
2
+
3
+ attr_accessor :is_running
4
+
5
+ def initialize
6
+ @threads = []
7
+ @is_running = false
8
+
9
+ @retry_exceeded_block = nil
10
+ end
11
+
12
+ def start(queue, options = {}, &block)
13
+ configure(queue, options)
14
+
15
+ puts '[QUEUE_WORKER] Listening for messages.'
16
+
17
+ raise 'Worker is already running.' if running?
18
+
19
+ @is_running = true
20
+ @threads = []
21
+
22
+ #loop through each thread count
23
+ @thread_count.times do
24
+ thr = Thread.new do
25
+
26
+ client = AwsQueueClient.new
27
+ manager = AwsQueueManager.new
28
+
29
+ #begin the queue loop for this thread
30
+ while true do
31
+
32
+ #check if the worker is still allowed to run and break out of thread loop if not
33
+ if !@is_running
34
+ break
35
+ end
36
+
37
+ #get the queue
38
+ q = manager.get_queue(queue)
39
+
40
+ received = false
41
+ error = false
42
+
43
+ begin
44
+
45
+ #request a message from the queue
46
+ response = client.sqs.receive_message({
47
+ queue_url: q,
48
+ max_number_of_messages: 1,
49
+ wait_time_seconds: 1,
50
+ message_attribute_names: ['ApproximateReceiveCount']
51
+ })
52
+
53
+ #check that a message was received
54
+ if response.messages.length > 0
55
+
56
+ msg = response.messages[0]
57
+ retry_attempts = msg.message_attributes['ApproximateReceiveCount'].to_i
58
+
59
+ #deserialize the message payload
60
+ message = Oj.load(msg.body)
61
+ payload = Oj.load(message["Message"])
62
+
63
+ puts "[QUEUE_WORKER] Message received. Retry Attempts: #{retry_attempts}"
64
+
65
+ #begin worker block for queue message
66
+ begin
67
+ block.call(payload.content, payload.type, retry_attempts)
68
+
69
+ #accept the message as processed
70
+ client.sqs.delete_message({ queue_url: q, receipt_handle: msg.receipt_handle })
71
+ puts '[QUEUE_WORKER] Message acknowledged.'
72
+ received = true
73
+ rescue => e
74
+ puts '[QUEUE_WORKER] An unhandled error happened attempting to process a queue message.'
75
+ puts "Error: #{e}"
76
+
77
+ error = true
78
+ puts '[QUEUE_WORKER] Message rejected.'
79
+
80
+ if !queue.allow_retry
81
+ #remove the message from the queue so that it does not get retried
82
+ client.sqs.delete_message({ queue_url: q, receipt_handle: msg.receipt_handle })
83
+ end
84
+
85
+ end
86
+
87
+ end
88
+
89
+ rescue
90
+ puts 'An error occured attempting to retrieve a message from the queue.'
91
+ end
92
+
93
+ #check if any message was received
94
+ if !received && !error
95
+ puts "[QUEUE_WORKER] No message received. Sleeping for #{@sleep} seconds"
96
+ #no message received so sleep before attempting to pop another message from the queue
97
+ sleep(@sleep)
98
+ end
99
+
100
+ end
101
+
102
+ end
103
+ @threads.push(thr)
104
+
105
+ end
106
+
107
+ if options.key?(:wait) && options[:wait] == true
108
+ @threads.each { |thr| thr.join }
109
+ end
110
+ end
111
+
112
+ def stop
113
+ @is_running = false
114
+ @threads.each { |thr| thr.join }
115
+ end
116
+
117
+ def on_retry_exceeded(&block)
118
+ @retry_exceeded_block = block
119
+ end
120
+
121
+ def running?
122
+ @is_running
123
+ end
124
+
125
+ private
126
+
127
+ def configure(queue, options = {})
128
+
129
+ @queue = queue
130
+
131
+ #default thread count
132
+ @thread_count = 5
133
+ if options.key?(:thread_count)
134
+ @thread_count = options[:thread_count]
135
+ end
136
+
137
+ #default sleep time in seconds
138
+ @sleep = 15
139
+ if options.key?(:sleep)
140
+ @sleep = options[:sleep]
141
+ end
142
+
143
+ end
144
+
145
+ end
@@ -0,0 +1,53 @@
1
+ class AwsSubscriptionManager
2
+
3
+ def initialize
4
+ @client = AwsQueueClient.new
5
+ @manager = AwsQueueManager.new
6
+ end
7
+
8
+ def subscribe(event_type, queue)
9
+
10
+ topic_arn = @client.get_topic_arn(event_type)
11
+
12
+ q = @manager.get_queue(queue)
13
+ queue_arn = @client.get_queue_arn(queue)
14
+
15
+ @client.sqs.set_queue_attributes({
16
+ queue_url: q,
17
+ attributes:{
18
+ 'Policy' => '{
19
+ "Version": "2012-10-17",
20
+ "Id": "SNStoSQS",
21
+ "Statement": [
22
+ {
23
+ "Sid":"rule1",
24
+ "Effect": "Allow",
25
+ "Principal": "*",
26
+ "Action": "sqs:*",
27
+ "Resource": "' + queue_arn + '",
28
+ "Condition" : {
29
+ "ArnEquals" : {
30
+ "aws:SourceArn":"' + topic_arn + '"
31
+ }
32
+ }
33
+ }
34
+ ]
35
+ }'
36
+ }
37
+ })
38
+
39
+ @client.sns.subscribe({
40
+ topic_arn: topic_arn,
41
+ protocol: 'sqs',
42
+ endpoint: queue_arn
43
+ })
44
+
45
+ end
46
+
47
+ def unsubscribe(queue)
48
+
49
+ raise 'Not implemented. Please unsubscribe the queue from the topic inside the AWS Management Console.'
50
+
51
+ end
52
+
53
+ end
@@ -0,0 +1,3 @@
1
+ module EventqAws
2
+ VERSION = "0.1.0"
3
+ end
data/lib/eventq_aws.rb ADDED
@@ -0,0 +1,6 @@
1
+ require "eventq_aws/version"
2
+ require 'eventq_aws/aws_eventq_client'
3
+ require 'eventq_aws/aws_queue_client'
4
+ require 'eventq_aws/aws_queue_manager'
5
+ require 'eventq_aws/aws_queue_worker'
6
+ require 'eventq_aws/aws_subscription_manager'
metadata ADDED
@@ -0,0 +1,152 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: eventq_aws
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - vaughanbrittonsage
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2016-04-29 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.11'
20
+ type: :development
21
+ prerelease: false
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
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
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
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: pry
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: oj
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: aws-sdk-core
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: eventq_base
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :runtime
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ description: This is the aws implementation for EventQ
112
+ email:
113
+ - vaughanbritton@gmail.com
114
+ executables: []
115
+ extensions: []
116
+ extra_rdoc_files: []
117
+ files:
118
+ - bin/console
119
+ - bin/setup
120
+ - lib/eventq_aws.rb
121
+ - lib/eventq_aws/aws_eventq_client.rb
122
+ - lib/eventq_aws/aws_queue_client.rb
123
+ - lib/eventq_aws/aws_queue_manager.rb
124
+ - lib/eventq_aws/aws_queue_worker.rb
125
+ - lib/eventq_aws/aws_subscription_manager.rb
126
+ - lib/eventq_aws/version.rb
127
+ homepage: https://github.com/vaughanbrittonsage/eventq
128
+ licenses:
129
+ - MIT
130
+ metadata: {}
131
+ post_install_message:
132
+ rdoc_options: []
133
+ require_paths:
134
+ - lib
135
+ required_ruby_version: !ruby/object:Gem::Requirement
136
+ requirements:
137
+ - - ">="
138
+ - !ruby/object:Gem::Version
139
+ version: '0'
140
+ required_rubygems_version: !ruby/object:Gem::Requirement
141
+ requirements:
142
+ - - ">="
143
+ - !ruby/object:Gem::Version
144
+ version: '0'
145
+ requirements: []
146
+ rubyforge_project:
147
+ rubygems_version: 2.5.1
148
+ signing_key:
149
+ specification_version: 4
150
+ summary: This is the aws implementation for EventQ
151
+ test_files: []
152
+ has_rdoc: