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
         |