active_elastic_job 1.7.0 → 2.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
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d8e455f174d4846927c18875dd2e1f645a87f870
|
4
|
+
data.tar.gz: 3cd316cd0b53a07cbf66234ccbb2ec71f5fe6e61
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d7ef1844c86ce29e4a93e0184eca63e879b0d43bcc08d1e35ab7573a08975e6943f8eb489028d4f47960780ab60743cbefc760961dd25b3cf49ed49500a00d9b
|
7
|
+
data.tar.gz: e0e5d7390144a3ebf53c756dc7a56436e14dabf4a6e2e37765fefff5625568a93669b7c8623b1f3aa1124c148938468e46d9059d59f604d2f85cb89b9d917798
|
@@ -5,7 +5,13 @@ module ActiveElasticJob
|
|
5
5
|
# This middleware intercepts requests which are sent by the SQS daemon
|
6
6
|
# running in {Amazon Elastic Beanstalk worker environments}[http://docs.aws.amazon.com/elasticbeanstalk/latest/dg/using-features-managing-env-tiers.html].
|
7
7
|
# It does this by looking at the +User-Agent+ header.
|
8
|
-
#
|
8
|
+
# Requesets from the SQS daemon are handled in two alternative cases:
|
9
|
+
#
|
10
|
+
# (1) the processed SQS message was originally triggered by a periodic task
|
11
|
+
# supported by Elastic Beanstalk's Periodic Task feature
|
12
|
+
#
|
13
|
+
# (2) the processed SQS message was queued by this gem representing an active job.
|
14
|
+
# In this case it verifies the digest which is sent along with a legit SQS
|
9
15
|
# message, and passed as an HTTP header in the resulting request.
|
10
16
|
# The digest is based on Rails' +secrets.secret_key_base+.
|
11
17
|
# Therefore, the application running in the web environment, which generates
|
@@ -13,14 +19,13 @@ module ActiveElasticJob
|
|
13
19
|
# environment, which verifies the digest, have to use the *same*
|
14
20
|
# +secrets.secret_key_base+ setting.
|
15
21
|
class SqsMessageConsumer
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
DOCKER_HOST_IP = "172.17.0.1".freeze
|
22
|
+
OK_RESPONSE = [ '200'.freeze, { 'Content-Type'.freeze => 'text/plain'.freeze }, [ 'OK'.freeze ] ]
|
23
|
+
FORBIDDEN_RESPONSE = [
|
24
|
+
'403'.freeze,
|
25
|
+
{ 'Content-Type'.freeze => 'text/plain'.freeze },
|
26
|
+
[ 'Request forbidden!'.freeze ]
|
27
|
+
]
|
28
|
+
DOCKER_HOST_IP = '172.17.0.1'.freeze
|
24
29
|
|
25
30
|
def initialize(app) #:nodoc:
|
26
31
|
@app = app
|
@@ -28,25 +33,22 @@ module ActiveElasticJob
|
|
28
33
|
|
29
34
|
def call(env) #:nodoc:
|
30
35
|
request = ActionDispatch::Request.new env
|
31
|
-
if enabled? && aws_sqsd?(request)
|
36
|
+
if enabled? && aws_sqsd?(request)
|
32
37
|
unless request.local? || sent_from_docker_host?(request)
|
33
|
-
|
34
|
-
return ['403', {CONTENT_TYPE_HEADER_NAME => 'text/plain' }, [ m ]]
|
38
|
+
return FORBIDDEN_RESPONSE
|
35
39
|
end
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
40
|
+
|
41
|
+
if periodic_task?(request)
|
42
|
+
execute_periodic_task(request)
|
43
|
+
return OK_RESPONSE
|
44
|
+
elsif originates_from_gem?(request)
|
45
|
+
begin
|
46
|
+
execute_job(request)
|
47
|
+
rescue ActiveElasticJob::MessageVerifier::InvalidDigest => e
|
48
|
+
return FORBIDDEN_RESPONSE
|
49
|
+
end
|
50
|
+
return OK_RESPONSE
|
45
51
|
end
|
46
|
-
return [
|
47
|
-
OK_RESPONSE_CODE ,
|
48
|
-
{CONTENT_TYPE_HEADER_NAME => CONTENT_TYPE },
|
49
|
-
[ '' ]]
|
50
52
|
end
|
51
53
|
@app.call(env)
|
52
54
|
end
|
@@ -54,35 +56,61 @@ module ActiveElasticJob
|
|
54
56
|
private
|
55
57
|
|
56
58
|
def enabled?
|
57
|
-
|
58
|
-
var == nil || var == 'false'.freeze
|
59
|
+
Rails.application.config.active_elastic_job.process_jobs == true
|
59
60
|
end
|
60
61
|
|
61
62
|
def verify!(request)
|
62
|
-
secret_key_base = Rails.application.secrets[:secret_key_base]
|
63
63
|
@verifier ||= ActiveElasticJob::MessageVerifier.new(secret_key_base)
|
64
|
-
digest = request.headers[
|
64
|
+
digest = request.headers['HTTP_X_AWS_SQSD_ATTR_MESSAGE_DIGEST'.freeze]
|
65
65
|
message = request.body_stream.read
|
66
66
|
request.body_stream.rewind
|
67
67
|
@verifier.verify!(message, digest)
|
68
68
|
end
|
69
69
|
|
70
|
+
def secret_key_base
|
71
|
+
config.secret_key_base
|
72
|
+
end
|
73
|
+
|
74
|
+
def config
|
75
|
+
Rails.application.config.active_elastic_job
|
76
|
+
end
|
77
|
+
|
70
78
|
def aws_sqsd?(request)
|
71
|
-
#
|
79
|
+
# Does not match against a Regexp
|
72
80
|
# in order to avoid performance penalties.
|
73
|
-
# Instead
|
81
|
+
# Instead performs a simple string comparison.
|
74
82
|
# Benchmark runs showed an performance increase of
|
75
83
|
# up to 40%
|
76
84
|
current_user_agent = request.headers['User-Agent'.freeze]
|
77
85
|
return (current_user_agent.present? &&
|
78
|
-
current_user_agent.size >=
|
79
|
-
current_user_agent[0..(
|
86
|
+
current_user_agent.size >= 'aws-sqsd'.freeze.size &&
|
87
|
+
current_user_agent[0..('aws-sqsd'.freeze.size - 1)] == 'aws-sqsd'.freeze)
|
88
|
+
end
|
89
|
+
|
90
|
+
def periodic_tasks_route
|
91
|
+
@periodic_tasks_route ||= config.periodic_tasks_route
|
92
|
+
end
|
93
|
+
|
94
|
+
def periodic_task?(request)
|
95
|
+
!request.fullpath.nil? && request.fullpath[0..(periodic_tasks_route.size - 1)] == periodic_tasks_route
|
96
|
+
end
|
97
|
+
|
98
|
+
def execute_job(request)
|
99
|
+
verify!(request)
|
100
|
+
job = JSON.load(request.body)
|
101
|
+
ActiveJob::Base.execute(job)
|
102
|
+
end
|
103
|
+
|
104
|
+
def execute_periodic_task(request)
|
105
|
+
job_name = request.headers['X-Aws-Sqsd-Taskname']
|
106
|
+
job = job_name.constantize.new
|
107
|
+
job.perform_now
|
80
108
|
end
|
81
109
|
|
82
110
|
def originates_from_gem?(request)
|
83
|
-
if request.headers[
|
111
|
+
if request.headers['HTTP_X_AWS_SQSD_ATTR_ORIGIN'.freeze] == ActiveElasticJob::ACRONYM
|
84
112
|
return true
|
85
|
-
elsif request.headers[
|
113
|
+
elsif request.headers['HTTP_X_AWS_SQSD_ATTR_MESSAGE_DIGEST'.freeze] != nil
|
86
114
|
return true
|
87
115
|
else
|
88
116
|
return false
|
@@ -90,7 +118,11 @@ module ActiveElasticJob
|
|
90
118
|
end
|
91
119
|
|
92
120
|
def sent_from_docker_host?(request)
|
93
|
-
|
121
|
+
app_runs_in_docker_container? && request.remote_ip == DOCKER_HOST_IP
|
122
|
+
end
|
123
|
+
|
124
|
+
def app_runs_in_docker_container?
|
125
|
+
@app_in_docker_container ||= `[ -f /proc/1/cgroup ] && cat /proc/1/cgroup` =~ /docker/
|
94
126
|
end
|
95
127
|
end
|
96
128
|
end
|
@@ -1,14 +1,16 @@
|
|
1
1
|
module ActiveElasticJob
|
2
2
|
class Railtie < Rails::Railtie
|
3
3
|
config.active_elastic_job = ActiveSupport::OrderedOptions.new
|
4
|
-
config.active_elastic_job.
|
5
|
-
config.active_elastic_job.
|
6
|
-
config.active_elastic_job.
|
7
|
-
config.active_elastic_job.disable_sqs_confumer = ENV['DISABLE_SQS_CONSUMER']
|
4
|
+
config.active_elastic_job.process_jobs = ENV['PROCESS_ACTIVE_ELASTIC_JOBS'] == 'true' || false
|
5
|
+
config.active_elastic_job.aws_credentials = Aws::InstanceProfileCredentials.new
|
6
|
+
config.active_elastic_job.periodic_tasks_route = '/periodic_tasks'.freeze
|
8
7
|
|
9
8
|
initializer "active_elastic_job.insert_middleware" do |app|
|
10
|
-
|
11
|
-
|
9
|
+
if app.config.active_elastic_job.secret_key_base.blank?
|
10
|
+
app.config.active_elastic_job.secret_key_base = app.secrets[:secret_key_base]
|
11
|
+
end
|
12
|
+
|
13
|
+
if app.config.active_elastic_job.process_jobs == true
|
12
14
|
if app.config.force_ssl
|
13
15
|
app.config.middleware.insert_before(ActionDispatch::SSL,ActiveElasticJob::Rack::SqsMessageConsumer)
|
14
16
|
else
|
@@ -19,12 +19,6 @@ module ActiveJob
|
|
19
19
|
MAX_MESSAGE_SIZE = (256 * 1024)
|
20
20
|
MAX_DELAY_IN_MINUTES = 15
|
21
21
|
|
22
|
-
if Gem::Version.new(Aws::VERSION) >= Gem::Version.new('2.2.19')
|
23
|
-
AWS_CLIENT_VERIFIES_MD5_DIGESTS = true
|
24
|
-
else
|
25
|
-
AWS_CLIENT_VERIFIES_MD5_DIGESTS = false
|
26
|
-
end
|
27
|
-
|
28
22
|
extend ActiveElasticJob::MD5MessageDigestCalculation
|
29
23
|
|
30
24
|
class Error < RuntimeError; end;
|
@@ -56,14 +50,15 @@ module ActiveJob
|
|
56
50
|
# #..
|
57
51
|
# end
|
58
52
|
class NonExistentQueue < Error
|
59
|
-
def initialize(queue_name)
|
53
|
+
def initialize(queue_name, aws_region)
|
60
54
|
|
61
55
|
super(<<-MSG)
|
62
56
|
The job is bound to queue at #{queue_name}.
|
63
57
|
Unfortunately a queue with this name does not exist in this
|
64
58
|
region. Either create an Amazon SQS queue named #{queue_name} -
|
65
59
|
you can do this in AWS console, make sure to select region
|
66
|
-
'#{
|
60
|
+
'#{aws_region}' - or you
|
61
|
+
select another queue for your jobs.
|
67
62
|
MSG
|
68
63
|
end
|
69
64
|
end
|
@@ -111,7 +106,7 @@ module ActiveJob
|
|
111
106
|
@queue_urls[job.queue_name.to_s] = nil
|
112
107
|
retry
|
113
108
|
end
|
114
|
-
raise NonExistentQueue,
|
109
|
+
raise NonExistentQueue.new(job, aws_region)
|
115
110
|
rescue Aws::Errors::ServiceError => e
|
116
111
|
raise Error, "Could not enqueue job, #{e.message}"
|
117
112
|
end
|
@@ -119,7 +114,7 @@ module ActiveJob
|
|
119
114
|
private
|
120
115
|
|
121
116
|
def aws_client_verifies_md5_digests?
|
122
|
-
|
117
|
+
Gem::Version.new(Aws::VERSION) >= Gem::Version.new('2.2.19'.freeze)
|
123
118
|
end
|
124
119
|
|
125
120
|
def build_message(queue_name, serialized_job, timestamp)
|
@@ -171,17 +166,19 @@ module ActiveJob
|
|
171
166
|
end
|
172
167
|
|
173
168
|
def aws_sqs_client
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
169
|
+
@aws_sqs_client ||= Aws::SQS::Client.new(credentials: aws_sqs_client_credentials )
|
170
|
+
end
|
171
|
+
|
172
|
+
def aws_sqs_client_credentials
|
173
|
+
config.aws_credentials
|
174
|
+
end
|
175
|
+
|
176
|
+
def aws_region
|
177
|
+
config.aws_region
|
178
|
+
end
|
179
|
+
|
180
|
+
def config
|
181
|
+
Rails.application.config.active_elastic_job
|
185
182
|
end
|
186
183
|
|
187
184
|
def message_digest(messsage_body)
|
@@ -206,7 +203,7 @@ module ActiveJob
|
|
206
203
|
end
|
207
204
|
|
208
205
|
def secret_key_base
|
209
|
-
|
206
|
+
config.secret_key_base
|
210
207
|
end
|
211
208
|
end
|
212
209
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: active_elastic_job
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 2.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tawan Sierek
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-11-
|
11
|
+
date: 2016-11-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: aws-sdk
|