active_elastic_job 1.7.0 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
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
|