active_elastic_job2 2.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: c07318b8577b4c3f4dd20abd95d232c734c09b46a772ecb828f3a5b8b80f4426
4
+ data.tar.gz: 334a44c79aeca8b35dbd87a79c0323605dc8eb0d3f8ed84bb74ef6ee8a490bc3
5
+ SHA512:
6
+ metadata.gz: 10d52fb153a3cc695affc5275fc3d52ff08f200a0677dd93d8a779e3501132154df59de6c7ec7e846721abbaabc1562da4ab32321f8abaa26e28b57f8e13393a
7
+ data.tar.gz: 1ff0bb9431ffe9fe46196358ef0ed60bac37c38b583b57cbbe95b09626b1000cb259af94c2e556b0d9441ca8edfc4fd79ac04c6d9f631c2e37602fd826b88afe
@@ -0,0 +1,27 @@
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_job2'
10
+ spec.version = ActiveElasticJob.version
11
+ spec.authors = ['unchi']
12
+ spec.email = ['developer.japan@gmail.com']
13
+ spec.summary = 'Active Elastic Job is a simple to use Active Job backend for Rails applications deployed on the Amazon Elastic Beanstalk platform.'
14
+ spec.description = 'Run background jobs / tasks of Rails applications deployed in Amazon Elastic Beanstalk environments. Active Elastic Job is an Active Job backend which is easy to setup. No need for customised container commands or other workarounds.'
15
+ spec.license = 'MIT'
16
+ spec.homepage = 'https://github.com/unchi/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_dependency 'aws-sdk-sqs', '~> 1'
26
+ spec.add_dependency 'rails', '>= 4.2'
27
+ end
@@ -0,0 +1,12 @@
1
+ require 'aws-sdk-core'
2
+ require 'active_elastic_job/version'
3
+ require 'active_elastic_job/md5_message_digest_calculation'
4
+ require 'active_job/queue_adapters/active_elastic_job_adapter'
5
+ require 'active_elastic_job/rack/sqs_message_consumer'
6
+ require 'active_elastic_job/message_verifier'
7
+
8
+ module ActiveElasticJob
9
+ ACRONYM = 'AEJ'.freeze
10
+ end
11
+
12
+ require "active_elastic_job/railtie" if defined? Rails
@@ -0,0 +1,72 @@
1
+ require 'openssl'
2
+ module ActiveElasticJob
3
+ # This module provides methods that calculate the MD5 digest for Amazon
4
+ # SQS message bodies and message attributes.
5
+ # The digest can be used to verify that Amazon SQS received the message
6
+ # correctly.
7
+ #
8
+ # Example:
9
+ #
10
+ # extend ActiveElasticJob::MD5MessageDigestCalculation
11
+ #
12
+ # resp = Aws::SQS::Client.new.send_message(
13
+ # queue_url: queue_url,
14
+ # message_body: body,
15
+ # message_attributes: attributes
16
+ # )
17
+ #
18
+ # if resp.md5_of_message_body != md5_of_message_body(body)
19
+ # raise "Returned digest of message body is invalid!"
20
+ # end
21
+ #
22
+ # if resp.md5_of_message_attributes != md5_of_message_attributes(attributes)
23
+ # raise "Returned digest of message attributes is invalid!"
24
+ # end
25
+ module MD5MessageDigestCalculation
26
+ TRANSPORT_TYPE_ENCODINGS = {
27
+ 'String' => 1,
28
+ 'Binary' => 2,
29
+ 'Number' => 1
30
+ }
31
+
32
+ NORMALIZED_ENCODING = Encoding::UTF_8
33
+
34
+ def md5_of_message_body(message_body)
35
+ OpenSSL::Digest::MD5.hexdigest(message_body)
36
+ end
37
+
38
+ def md5_of_message_attributes(message_attributes)
39
+ encoded = { }
40
+ message_attributes.each do |name, attribute|
41
+ name = name.to_s
42
+ encoded[name] = String.new
43
+ encoded[name] << encode_length_and_bytes(name) <<
44
+ encode_length_and_bytes(attribute[:data_type]) <<
45
+ [TRANSPORT_TYPE_ENCODINGS[attribute[:data_type]]].pack('C'.freeze)
46
+
47
+ if attribute[:string_value] != nil
48
+ encoded[name] << encode_length_and_string(attribute[:string_value])
49
+ elsif attribute[:binary_value] != nil
50
+ encoded[name] << encode_length_and_bytes(attribute[:binary_value])
51
+ end
52
+ end
53
+
54
+ buffer = encoded.keys.sort.reduce(String.new) do |string, name|
55
+ string << encoded[name]
56
+ end
57
+ OpenSSL::Digest::MD5.hexdigest(buffer)
58
+ end
59
+
60
+ private
61
+
62
+ def encode_length_and_string(string)
63
+ string = String.new(string)
64
+ string.encode!(NORMALIZED_ENCODING)
65
+ encode_length_and_bytes(string)
66
+ end
67
+
68
+ def encode_length_and_bytes(bytes)
69
+ [bytes.bytesize, bytes].pack('L>a*'.freeze)
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,34 @@
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
+ return false
19
+ end
20
+
21
+ return ActiveSupport::SecurityUtils.secure_compare(
22
+ digest, generate_digest(message))
23
+ end
24
+
25
+ def verify!(message, digest)
26
+ raise InvalidDigest unless verify(message, digest)
27
+ end
28
+
29
+ def generate_digest(message)
30
+ require 'openssl' unless defined?(OpenSSL)
31
+ OpenSSL::HMAC.hexdigest(OpenSSL::Digest::SHA1.new, @secret, message)
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,129 @@
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
+ # 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
15
+ # message, and passed as an HTTP header in the resulting request.
16
+ # The digest is based on Rails' +secrets.secret_key_base+.
17
+ # Therefore, the application running in the web environment, which generates
18
+ # the digest, and the application running in the worker
19
+ # environment, which verifies the digest, have to use the *same*
20
+ # +secrets.secret_key_base+ setting.
21
+ class SqsMessageConsumer
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
29
+
30
+ def initialize(app) #:nodoc:
31
+ @app = app
32
+ end
33
+
34
+ def call(env) #:nodoc:
35
+ request = ActionDispatch::Request.new env
36
+ if enabled? && aws_sqsd?(request)
37
+ unless request.local? || sent_from_docker_host?(request)
38
+ return FORBIDDEN_RESPONSE
39
+ end
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
51
+ end
52
+ end
53
+ @app.call(env)
54
+ end
55
+
56
+ private
57
+
58
+ def enabled?
59
+ Rails.application.config.active_elastic_job.process_jobs == true
60
+ end
61
+
62
+ def verify!(request)
63
+ @verifier ||= ActiveElasticJob::MessageVerifier.new(secret_key_base)
64
+ digest = request.headers['HTTP_X_AWS_SQSD_ATTR_MESSAGE_DIGEST'.freeze]
65
+ message = request.body_stream.read
66
+ request.body_stream.rewind
67
+ @verifier.verify!(message, digest)
68
+ end
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
+
78
+ def aws_sqsd?(request)
79
+ # Does not match against a Regexp
80
+ # in order to avoid performance penalties.
81
+ # Instead performs a simple string comparison.
82
+ # Benchmark runs showed an performance increase of
83
+ # up to 40%
84
+ current_user_agent = request.headers['User-Agent'.freeze]
85
+ return (current_user_agent.present? &&
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
108
+ end
109
+
110
+ def originates_from_gem?(request)
111
+ if request.headers['HTTP_X_AWS_SQSD_ATTR_ORIGIN'.freeze] == ActiveElasticJob::ACRONYM
112
+ return true
113
+ elsif request.headers['HTTP_X_AWS_SQSD_ATTR_MESSAGE_DIGEST'.freeze] != nil
114
+ return true
115
+ else
116
+ return false
117
+ end
118
+ end
119
+
120
+ def sent_from_docker_host?(request)
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/
126
+ end
127
+ end
128
+ end
129
+ end
@@ -0,0 +1,23 @@
1
+ module ActiveElasticJob
2
+ class Railtie < Rails::Railtie
3
+ config.active_elastic_job = ActiveSupport::OrderedOptions.new
4
+ process_active_elastic_jobs = ENV['PROCESS_ACTIVE_ELASTIC_JOBS']
5
+ config.active_elastic_job.process_jobs = !process_active_elastic_jobs.nil? && process_active_elastic_jobs.downcase == 'true'
6
+ config.active_elastic_job.aws_credentials = lambda { Aws::InstanceProfileCredentials.new }
7
+ config.active_elastic_job.periodic_tasks_route = '/periodic_tasks'.freeze
8
+
9
+ initializer "active_elastic_job.insert_middleware" do |app|
10
+ if app.config.active_elastic_job.secret_key_base.blank?
11
+ app.config.active_elastic_job.secret_key_base = app.secrets[:secret_key_base]
12
+ end
13
+
14
+ if app.config.active_elastic_job.process_jobs == true
15
+ if app.config.force_ssl
16
+ app.config.middleware.insert_before(ActionDispatch::SSL,ActiveElasticJob::Rack::SqsMessageConsumer)
17
+ else
18
+ app.config.middleware.use(ActiveElasticJob::Rack::SqsMessageConsumer)
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,18 @@
1
+ module ActiveElasticJob
2
+ module VERSION
3
+ MAJOR = 2
4
+ MINOR = 0
5
+ TINY = 2
6
+ PRE = nil
7
+
8
+ STRING = [MAJOR, MINOR, TINY, PRE].compact.join('.')
9
+
10
+ def self.to_s
11
+ STRING
12
+ end
13
+ end
14
+
15
+ def self.version
16
+ VERSION::STRING
17
+ end
18
+ end
@@ -0,0 +1,221 @@
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,
12
+ # see <tt>ActiveJob::Base.queue_as</tt>
13
+ #
14
+ # To use Active Elastic Job, set the queue_adapter config
15
+ # to +:active_elastic_job+.
16
+ #
17
+ # Rails.application.config.active_job.queue_adapter = :active_elastic_job
18
+ class ActiveElasticJobAdapter
19
+ MAX_MESSAGE_SIZE = (256 * 1024)
20
+ MAX_DELAY_IN_MINUTES = 15
21
+
22
+ extend ActiveElasticJob::MD5MessageDigestCalculation
23
+
24
+ class Error < RuntimeError; end;
25
+
26
+ # Raised when job exceeds 256 KB in its serialized form. The limit is
27
+ # imposed by Amazon SQS.
28
+ class SerializedJobTooBig < Error
29
+ def initialize(serialized_job)
30
+ super(<<-MSG)
31
+ The job contains #{serialized_job.bytesize} bytes in its serialzed form,
32
+ which exceeds the allowed maximum of #{MAX_MESSAGE_SIZE} bytes imposed by Amazon SQS.
33
+ MSG
34
+ end
35
+ end
36
+
37
+ # Raised when job queue does not exist. The job queue is determined by
38
+ # <tt>ActiveJob::Base.queue_as</tt>. You can either: (1) create a new
39
+ # Amazon SQS queue and attach a worker environment to it, or (2) select a
40
+ # different queue for your jobs.
41
+ #
42
+ # Example:
43
+ # * Open your AWS console and create an SQS queue named +high_priority+ in
44
+ # the same AWS region of your Elastic Beanstalk environments.
45
+ # * Queue your jobs accordingly:
46
+ #
47
+ # class MyJob < ActiveJob::Base
48
+ # queue_as :high_priority
49
+ # #..
50
+ # end
51
+ class NonExistentQueue < Error
52
+ def initialize(queue_name, aws_region)
53
+
54
+ super(<<-MSG)
55
+ The job is bound to queue at #{queue_name}.
56
+ Unfortunately a queue with this name does not exist in this
57
+ region. Either create an Amazon SQS queue named #{queue_name} -
58
+ you can do this in AWS console, make sure to select region
59
+ '#{aws_region}' - or you
60
+ select another queue for your jobs.
61
+ MSG
62
+ end
63
+ end
64
+
65
+ # Raised when calculated MD5 digest does not match the MD5 Digest
66
+ # of the response from Amazon SQS.
67
+ class MD5MismatchError < Error
68
+ def initialize(message_id, calculated, returned)
69
+
70
+ super(<<-MSG)
71
+ MD5 '#{returned}' returned by Amazon SQS does not match the
72
+ calculation on the original request which was '#{calculated}'.
73
+ The message with Message ID #{message_id} sent to SQS might be
74
+ corrupted.
75
+ MSG
76
+ end
77
+ end
78
+
79
+ # Raised when the delay is longer than the MAX_DELAY_IN_MINUTES
80
+ class DelayTooLong < RangeError
81
+ def initialize()
82
+ super(<<-MSG)
83
+ Jobs cannot be scheduled more than #{MAX_DELAY_IN_MINUTES} minutes
84
+ into the future.
85
+ See http://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_SendMessage.html
86
+ for further details!
87
+ MSG
88
+ end
89
+ end
90
+
91
+ def enqueue(job) #:nodoc:
92
+ self.class.enqueue job
93
+ end
94
+
95
+ def enqueue_at(job, timestamp) #:nodoc:
96
+ self.class.enqueue_at(job, timestamp)
97
+ end
98
+
99
+ class << self
100
+ def enqueue(job) #:nodoc:
101
+ enqueue_at(job, Time.now)
102
+ end
103
+
104
+ def enqueue_at(job, timestamp) #:nodoc:
105
+ serialized_job = JSON.dump(job.serialize)
106
+ check_job_size!(serialized_job)
107
+ message = build_message(job.queue_name, serialized_job, timestamp)
108
+ resp = aws_sqs_client.send_message(message)
109
+ unless aws_client_verifies_md5_digests?
110
+ verify_md5_digests!(
111
+ resp,
112
+ message[:message_body],
113
+ message[:message_attributes])
114
+ end
115
+ rescue Aws::SQS::Errors::NonExistentQueue => e
116
+ unless @queue_urls[job.queue_name.to_s].nil?
117
+ @queue_urls[job.queue_name.to_s] = nil
118
+ retry
119
+ end
120
+ raise NonExistentQueue.new(job, aws_region)
121
+ rescue Aws::Errors::ServiceError => e
122
+ raise Error, "Could not enqueue job, #{e.message}"
123
+ end
124
+
125
+ private
126
+
127
+ def aws_client_verifies_md5_digests?
128
+ Gem::Version.new(Aws::CORE_GEM_VERSION) >= Gem::Version.new('2.2.19'.freeze)
129
+ end
130
+
131
+ def build_message(queue_name, serialized_job, timestamp)
132
+ {
133
+ queue_url: queue_url(queue_name),
134
+ message_body: serialized_job,
135
+ delay_seconds: calculate_delay(timestamp),
136
+ message_attributes: {
137
+ "message-digest".freeze => {
138
+ string_value: message_digest(serialized_job),
139
+ data_type: "String".freeze
140
+ },
141
+ origin: {
142
+ string_value: ActiveElasticJob::ACRONYM,
143
+ data_type: "String".freeze
144
+ }
145
+ }
146
+ }
147
+ end
148
+
149
+ def queue_url(queue_name)
150
+ cache_key = queue_name.to_s
151
+ @queue_urls ||= { }
152
+ return @queue_urls[cache_key] if @queue_urls[cache_key]
153
+ resp = aws_sqs_client.get_queue_url(queue_name: queue_name.to_s)
154
+ @queue_urls[cache_key] = resp.queue_url
155
+ rescue Aws::SQS::Errors::NonExistentQueue => e
156
+ raise NonExistentQueue.new(queue_name, aws_region)
157
+ end
158
+
159
+ def calculate_delay(timestamp)
160
+ delay = (timestamp - Time.current.to_f).to_i + 1
161
+ if delay > MAX_DELAY_IN_MINUTES.minutes
162
+ raise DelayTooLong.new
163
+ end
164
+ delay = 0 if delay < 0
165
+ delay
166
+ end
167
+
168
+ def check_job_size!(serialized_job)
169
+ if serialized_job.bytesize > MAX_MESSAGE_SIZE
170
+ raise SerializedJobTooBig, serialized_job
171
+ end
172
+ end
173
+
174
+ def aws_sqs_client
175
+ @aws_sqs_client ||= Aws::SQS::Client.new(region: aws_region, credentials: aws_sqs_client_credentials )
176
+ end
177
+
178
+ def aws_sqs_client_credentials
179
+ @aws_credentials ||= if config.aws_credentials.kind_of?(Proc)
180
+ config.aws_credentials.call
181
+ else
182
+ config.aws_credentials
183
+ end
184
+ end
185
+
186
+ def aws_region
187
+ config.aws_region
188
+ end
189
+
190
+ def config
191
+ Rails.application.config.active_elastic_job
192
+ end
193
+
194
+ def message_digest(messsage_body)
195
+ @verifier ||= ActiveElasticJob::MessageVerifier.new(secret_key_base)
196
+ @verifier.generate_digest(messsage_body)
197
+ end
198
+
199
+ def verify_md5_digests!(response, messsage_body, message_attributes)
200
+ calculated = md5_of_message_body(messsage_body)
201
+ returned = response.md5_of_message_body
202
+ if calculated != returned
203
+ raise MD5MismatchError.new response.message_id, calculated, returned
204
+ end
205
+
206
+ if message_attributes
207
+ calculated = md5_of_message_attributes(message_attributes)
208
+ returned = response.md5_of_message_attributes
209
+ if calculated != returned
210
+ raise MD5MismatchError.new response.message_id, calculated, returned
211
+ end
212
+ end
213
+ end
214
+
215
+ def secret_key_base
216
+ config.secret_key_base
217
+ end
218
+ end
219
+ end
220
+ end
221
+ end
metadata ADDED
@@ -0,0 +1,82 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: active_elastic_job2
3
+ version: !ruby/object:Gem::Version
4
+ version: 2.0.2
5
+ platform: ruby
6
+ authors:
7
+ - unchi
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2019-12-04 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: aws-sdk-sqs
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rails
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '4.2'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '4.2'
41
+ description: Run background jobs / tasks of Rails applications deployed in Amazon
42
+ Elastic Beanstalk environments. Active Elastic Job is an Active Job backend which
43
+ is easy to setup. No need for customised container commands or other workarounds.
44
+ email:
45
+ - developer.japan@gmail.com
46
+ executables: []
47
+ extensions: []
48
+ extra_rdoc_files: []
49
+ files:
50
+ - active-elastic-job.gemspec
51
+ - lib/active_elastic_job.rb
52
+ - lib/active_elastic_job/md5_message_digest_calculation.rb
53
+ - lib/active_elastic_job/message_verifier.rb
54
+ - lib/active_elastic_job/rack/sqs_message_consumer.rb
55
+ - lib/active_elastic_job/railtie.rb
56
+ - lib/active_elastic_job/version.rb
57
+ - lib/active_job/queue_adapters/active_elastic_job_adapter.rb
58
+ homepage: https://github.com/unchi/active-elastic-job
59
+ licenses:
60
+ - MIT
61
+ metadata: {}
62
+ post_install_message:
63
+ rdoc_options: []
64
+ require_paths:
65
+ - lib
66
+ required_ruby_version: !ruby/object:Gem::Requirement
67
+ requirements:
68
+ - - ">="
69
+ - !ruby/object:Gem::Version
70
+ version: 1.9.3
71
+ required_rubygems_version: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ requirements: []
77
+ rubygems_version: 3.0.1
78
+ signing_key:
79
+ specification_version: 4
80
+ summary: Active Elastic Job is a simple to use Active Job backend for Rails applications
81
+ deployed on the Amazon Elastic Beanstalk platform.
82
+ test_files: []