active_elastic_job 1.0.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 +7 -0
- data/active-elastic-job.gemspec +32 -0
- data/lib/active_elastic_job.rb +9 -0
- data/lib/active_elastic_job/message_verifier.rb +32 -0
- data/lib/active_elastic_job/rack/sqs_message_consumer.rb +47 -0
- data/lib/active_elastic_job/railtie.rb +7 -0
- data/lib/active_elastic_job/version.rb +3 -0
- data/lib/active_job/queue_adapters/active_elastic_job_adapter.rb +66 -0
- metadata +151 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: d19d4e4ef144ceabffd14c20daae3b285df14616
|
4
|
+
data.tar.gz: 70be0d9706ef4ae1f7a91d14380522e5263a2c31
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 829d4cd3713427e6b85ed76a0a9e212b63ad5ab1232c901d30f2ad5360db90af1e242ef0fe8f37c0d01475911ad3d88e8d5dfdb22c41e17fcc3d9f04c32f5486
|
7
|
+
data.tar.gz: 7cea59eaaa8091a0cfa95c103ef373874f31225223e60d87e5ce9c41b5135a9ab4db6099a66f5f6d0c384174372a838c947624e71e1a3b099b74cc905983b17d
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
|
5
|
+
require 'active_elastic_job/version'
|
6
|
+
|
7
|
+
Gem::Specification.new do |spec|
|
8
|
+
spec.platform = Gem::Platform::RUBY
|
9
|
+
spec.name = 'active_elastic_job'
|
10
|
+
spec.version = ActiveElasticJob::VERSION
|
11
|
+
spec.authors = ['Tawan Sierek']
|
12
|
+
spec.email = ['tawan@sierek.com']
|
13
|
+
spec.description = 'Active Elastic Job is a simple to use Active Job backend for Rails applications deployed on the Amazon Elastic Beanstalk platform.'
|
14
|
+
spec.summary = spec.description
|
15
|
+
spec.license = 'MIT'
|
16
|
+
spec.homepage = 'https://github.com/tawan/active-elastic-job'
|
17
|
+
|
18
|
+
spec.files = Dir.glob('lib/**/*') + [ 'active-elastic-job.gemspec' ]
|
19
|
+
spec.executables = []
|
20
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
21
|
+
spec.require_paths = ['lib']
|
22
|
+
|
23
|
+
spec.required_ruby_version = '>= 1.9.3'
|
24
|
+
|
25
|
+
spec.add_development_dependency 'bundler'
|
26
|
+
spec.add_development_dependency 'rspec', '~> 3.4'
|
27
|
+
spec.add_development_dependency 'dotenv'
|
28
|
+
spec.add_development_dependency 'fuubar'
|
29
|
+
spec.add_development_dependency 'rails', '~> 4.2'
|
30
|
+
spec.add_development_dependency 'rdoc'
|
31
|
+
spec.add_dependency 'aws-sdk', '~> 2'
|
32
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
require 'aws-sdk-core'
|
2
|
+
require 'active_elastic_job/version'
|
3
|
+
require 'active_job/queue_adapters/active_elastic_job_adapter'
|
4
|
+
require 'active_elastic_job/rack/sqs_message_consumer'
|
5
|
+
require 'active_elastic_job/message_verifier'
|
6
|
+
|
7
|
+
module ActiveElasticJob; end;
|
8
|
+
|
9
|
+
require "active_elastic_job/railtie" if defined? Rails
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'active_support/security_utils'
|
2
|
+
|
3
|
+
module ActiveElasticJob
|
4
|
+
class MessageVerifier #:nodoc:
|
5
|
+
|
6
|
+
# Raised when digest generated by
|
7
|
+
# <tt>ActiveJob::QueueAdapters::ActiveElasticJobAdapter</tt> could not
|
8
|
+
# be verified.
|
9
|
+
class InvalidDigest < StandardError
|
10
|
+
end
|
11
|
+
|
12
|
+
def initialize(secret)
|
13
|
+
@secret = secret
|
14
|
+
end
|
15
|
+
|
16
|
+
def verify(message, digest)
|
17
|
+
if message.nil? || message.blank? || digest.nil? || digest.blank?
|
18
|
+
raise InvalidDigest
|
19
|
+
end
|
20
|
+
|
21
|
+
unless ActiveSupport::SecurityUtils.secure_compare(digest, generate_digest(message))
|
22
|
+
raise InvalidDigest
|
23
|
+
end
|
24
|
+
true
|
25
|
+
end
|
26
|
+
|
27
|
+
def generate_digest(message)
|
28
|
+
require 'openssl' unless defined?(OpenSSL)
|
29
|
+
OpenSSL::HMAC.hexdigest(OpenSSL::Digest.const_get('SHA1').new, @secret, message)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require "action_dispatch"
|
2
|
+
|
3
|
+
module ActiveElasticJob
|
4
|
+
module Rack
|
5
|
+
# This middleware intercepts requests which are sent by the SQS daemon
|
6
|
+
# running in {Amazon Elastic Beanstalk worker environments}[http://docs.aws.amazon.com/elasticbeanstalk/latest/dg/using-features-managing-env-tiers.html].
|
7
|
+
# It does this by looking at the +User-Agent+ header.
|
8
|
+
# Furthermore, it verifies the digest which is sent along with a legit SQS message,
|
9
|
+
# and passed as an HTTP header in the resulting request.
|
10
|
+
# The digest is based on Rails' +secrets.secret_key_base+.
|
11
|
+
# Therefore, the application running in the web environment, which generates
|
12
|
+
# the digest, and the application running in the worker
|
13
|
+
# environment, which verifies the digest, have to use the *same*
|
14
|
+
# +secrets.secret_key_base+ setting.
|
15
|
+
class SqsMessageConsumer
|
16
|
+
def initialize(app) #:nodoc:
|
17
|
+
@app = app
|
18
|
+
end
|
19
|
+
|
20
|
+
def call(env) #:nodoc:
|
21
|
+
request = ActionDispatch::Request.new env
|
22
|
+
if request.headers['User-Agent'] =~ /aws-sqsd/
|
23
|
+
begin
|
24
|
+
verify(request)
|
25
|
+
job = JSON.load(request.body)
|
26
|
+
ActiveJob::Base.execute(job)
|
27
|
+
rescue ActiveElasticJob::MessageVerifier::InvalidDigest => e
|
28
|
+
return ['403', {'Content-Type' => env['text/plain'] }, ["incorrect digest"]]
|
29
|
+
rescue StandardError => e
|
30
|
+
return ['500', {'Content-Type' => env['text/plain'] }, [e.message]]
|
31
|
+
end
|
32
|
+
return ['200', {'Content-Type' => 'application/json' }, [ '' ]]
|
33
|
+
end
|
34
|
+
@app.call(env)
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def verify(request)
|
40
|
+
secret_key_base = Rails.application.secrets[:secret_key_base]
|
41
|
+
verifier = ActiveElasticJob::MessageVerifier.new(secret_key_base)
|
42
|
+
digest = request.headers['HTTP_X_AWS_SQSD_ATTR_MESSAGE_DIGEST']
|
43
|
+
verifier.verify(request.body.string, digest)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
module ActiveJob
|
2
|
+
module QueueAdapters
|
3
|
+
# == Active Elastic Job adapter for Active Job
|
4
|
+
#
|
5
|
+
# Active Elastic Job provides (1) an adapter (this class) for Rails'
|
6
|
+
# Active Job framework and (2) a Rack middleware to process job requests,
|
7
|
+
# which are sent by the SQS daemon running in {Amazon Elastic Beanstalk worker
|
8
|
+
# environments}[http://docs.aws.amazon.com/elasticbeanstalk/latest/dg/using-features-managing-env-tiers.html].
|
9
|
+
#
|
10
|
+
# This adapter serializes job objects and sends them as a message to an
|
11
|
+
# Amazon SQS queue specified by the job's queue name, see <tt>ActiveJob::Base.queue_as</tt>
|
12
|
+
#
|
13
|
+
# To use Active Elastic Job, set the queue_adapter config to +:active_elastic_job+.
|
14
|
+
#
|
15
|
+
# Rails.application.config.active_job.queue_adapter = :active_elastic_job
|
16
|
+
class ActiveElasticJobAdapter
|
17
|
+
class << self
|
18
|
+
def enqueue(job) #:nodoc:
|
19
|
+
enqueue_at(job, Time.now)
|
20
|
+
end
|
21
|
+
|
22
|
+
def enqueue_at(job, timestamp) #:nodoc:
|
23
|
+
queue_url = aws_sqs_client.create_queue(queue_name: job.queue_name.to_s).queue_url
|
24
|
+
message_body = JSON.dump(job.serialize)
|
25
|
+
delay = (timestamp - Time.current.to_f).to_i + 1
|
26
|
+
if delay > 15.minutes
|
27
|
+
msg =<<-MSG
|
28
|
+
Jobs cannot be scheduled more than 15 minutes into the future.
|
29
|
+
See http://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_SendMessage.html
|
30
|
+
for further details!
|
31
|
+
MSG
|
32
|
+
raise RangeError, 'The maximum allowed delay is 15 minutes' if delay > 15.minutes
|
33
|
+
end
|
34
|
+
|
35
|
+
aws_sqs_client.send_message(
|
36
|
+
queue_url: queue_url,
|
37
|
+
message_body: message_body,
|
38
|
+
delay_seconds: delay,
|
39
|
+
message_attributes: {
|
40
|
+
"message_digest" => {
|
41
|
+
string_value: message_digest(message_body),
|
42
|
+
data_type: "String"
|
43
|
+
}
|
44
|
+
}
|
45
|
+
)
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
|
50
|
+
def aws_sqs_client
|
51
|
+
Aws::SQS::Client.new(
|
52
|
+
access_key_id: ENV['AWS_ACCESS_KEY_ID'],
|
53
|
+
secret_access_key: ENV['AWS_SECRET_ACCESS_KEY'],
|
54
|
+
region: ENV['AWS_REGION']
|
55
|
+
)
|
56
|
+
end
|
57
|
+
|
58
|
+
def message_digest(messsage_body)
|
59
|
+
secret_key_base = Rails.application.secrets[:secret_key_base]
|
60
|
+
verifier = ActiveElasticJob::MessageVerifier.new(secret_key_base)
|
61
|
+
verifier.generate_digest(messsage_body)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
metadata
ADDED
@@ -0,0 +1,151 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: active_elastic_job
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Tawan Sierek
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-01-03 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: '0'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rspec
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '3.4'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '3.4'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: dotenv
|
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: fuubar
|
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: rails
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '4.2'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '4.2'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rdoc
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
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: aws-sdk
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '2'
|
104
|
+
type: :runtime
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - "~>"
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '2'
|
111
|
+
description: Active Elastic Job is a simple to use Active Job backend for Rails applications
|
112
|
+
deployed on the Amazon Elastic Beanstalk platform.
|
113
|
+
email:
|
114
|
+
- tawan@sierek.com
|
115
|
+
executables: []
|
116
|
+
extensions: []
|
117
|
+
extra_rdoc_files: []
|
118
|
+
files:
|
119
|
+
- active-elastic-job.gemspec
|
120
|
+
- lib/active_elastic_job.rb
|
121
|
+
- lib/active_elastic_job/message_verifier.rb
|
122
|
+
- lib/active_elastic_job/rack/sqs_message_consumer.rb
|
123
|
+
- lib/active_elastic_job/railtie.rb
|
124
|
+
- lib/active_elastic_job/version.rb
|
125
|
+
- lib/active_job/queue_adapters/active_elastic_job_adapter.rb
|
126
|
+
homepage: https://github.com/tawan/active-elastic-job
|
127
|
+
licenses:
|
128
|
+
- MIT
|
129
|
+
metadata: {}
|
130
|
+
post_install_message:
|
131
|
+
rdoc_options: []
|
132
|
+
require_paths:
|
133
|
+
- lib
|
134
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - ">="
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: 1.9.3
|
139
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
140
|
+
requirements:
|
141
|
+
- - ">="
|
142
|
+
- !ruby/object:Gem::Version
|
143
|
+
version: '0'
|
144
|
+
requirements: []
|
145
|
+
rubyforge_project:
|
146
|
+
rubygems_version: 2.4.5.1
|
147
|
+
signing_key:
|
148
|
+
specification_version: 4
|
149
|
+
summary: Active Elastic Job is a simple to use Active Job backend for Rails applications
|
150
|
+
deployed on the Amazon Elastic Beanstalk platform.
|
151
|
+
test_files: []
|