aws-sdk-rails 4.1.0 → 4.2.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 +4 -4
 - data/CHANGELOG.md +239 -0
 - data/LICENSE.txt +12 -0
 - data/VERSION +1 -1
 - data/lib/aws/rails/action_mailbox/rspec.rb +6 -65
 - data/lib/aws/rails/middleware/elastic_beanstalk_sqsd.rb +134 -0
 - data/lib/aws/rails/notifications.rb +3 -6
 - data/lib/aws/rails/railtie.rb +39 -40
 - data/lib/aws-sdk-rails.rb +16 -8
 - metadata +26 -152
 - data/app/controllers/action_mailbox/ingresses/ses/inbound_emails_controller.rb +0 -79
 - data/bin/aws_sqs_active_job +0 -6
 - data/config/routes.rb +0 -8
 - data/lib/action_dispatch/session/dynamodb_store.rb +0 -38
 - data/lib/active_job/queue_adapters/sqs_adapter/params.rb +0 -78
 - data/lib/active_job/queue_adapters/sqs_adapter.rb +0 -58
 - data/lib/active_job/queue_adapters/sqs_async_adapter.rb +0 -39
 - data/lib/aws/rails/action_mailbox/engine.rb +0 -21
 - data/lib/aws/rails/action_mailbox/rspec/email.rb +0 -50
 - data/lib/aws/rails/action_mailbox/rspec/subscription_confirmation.rb +0 -37
 - data/lib/aws/rails/action_mailbox/s3_client.rb +0 -28
 - data/lib/aws/rails/action_mailbox/sns_message_verifier.rb +0 -18
 - data/lib/aws/rails/action_mailbox/sns_notification.rb +0 -99
 - data/lib/aws/rails/middleware/ebs_sqs_active_job_middleware.rb +0 -118
 - data/lib/aws/rails/ses_mailer.rb +0 -49
 - data/lib/aws/rails/sesv2_mailer.rb +0 -60
 - data/lib/aws/rails/sqs_active_job/configuration.rb +0 -184
 - data/lib/aws/rails/sqs_active_job/deduplication.rb +0 -21
 - data/lib/aws/rails/sqs_active_job/executor.rb +0 -77
 - data/lib/aws/rails/sqs_active_job/job_runner.rb +0 -27
 - data/lib/aws/rails/sqs_active_job/lambda_handler.rb +0 -63
 - data/lib/aws/rails/sqs_active_job/poller.rb +0 -160
 - data/lib/aws/rails/sqs_active_job.rb +0 -33
 - data/lib/generators/aws_record/base.rb +0 -213
 - data/lib/generators/aws_record/generated_attribute.rb +0 -138
 - data/lib/generators/aws_record/model/USAGE +0 -24
 - data/lib/generators/aws_record/model/model_generator.rb +0 -25
 - data/lib/generators/aws_record/model/templates/model.erb +0 -48
 - data/lib/generators/aws_record/model/templates/table_config.erb +0 -18
 - data/lib/generators/aws_record/secondary_index.rb +0 -66
 - data/lib/generators/dynamo_db/session_store_migration/USAGE +0 -13
 - data/lib/generators/dynamo_db/session_store_migration/session_store_migration_generator.rb +0 -48
 - data/lib/generators/dynamo_db/session_store_migration/templates/dynamo_db_session_store.yml +0 -70
 - data/lib/generators/dynamo_db/session_store_migration/templates/session_store_migration.erb +0 -9
 - data/lib/tasks/aws_record/migrate.rake +0 -14
 - data/lib/tasks/dynamo_db/session_store.rake +0 -10
 
| 
         @@ -1,37 +0,0 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            # frozen_string_literal: true
         
     | 
| 
       2 
     | 
    
         
            -
             
     | 
| 
       3 
     | 
    
         
            -
            module Aws
         
     | 
| 
       4 
     | 
    
         
            -
              module Rails
         
     | 
| 
       5 
     | 
    
         
            -
                module ActionMailbox
         
     | 
| 
       6 
     | 
    
         
            -
                  module RSpec
         
     | 
| 
       7 
     | 
    
         
            -
                    # @api private
         
     | 
| 
       8 
     | 
    
         
            -
                    class SubscriptionConfirmation
         
     | 
| 
       9 
     | 
    
         
            -
                      def initialize(authentic: true, topic: 'topic:arn:default')
         
     | 
| 
       10 
     | 
    
         
            -
                        @authentic = authentic
         
     | 
| 
       11 
     | 
    
         
            -
                        @topic = topic
         
     | 
| 
       12 
     | 
    
         
            -
                      end
         
     | 
| 
       13 
     | 
    
         
            -
             
     | 
| 
       14 
     | 
    
         
            -
                      def url
         
     | 
| 
       15 
     | 
    
         
            -
                        '/rails/action_mailbox/ses/inbound_emails'
         
     | 
| 
       16 
     | 
    
         
            -
                      end
         
     | 
| 
       17 
     | 
    
         
            -
             
     | 
| 
       18 
     | 
    
         
            -
                      def headers
         
     | 
| 
       19 
     | 
    
         
            -
                        { 'content-type' => 'application/json' }
         
     | 
| 
       20 
     | 
    
         
            -
                      end
         
     | 
| 
       21 
     | 
    
         
            -
             
     | 
| 
       22 
     | 
    
         
            -
                      def params
         
     | 
| 
       23 
     | 
    
         
            -
                        {
         
     | 
| 
       24 
     | 
    
         
            -
                          'Type' => 'SubscriptionConfirmation',
         
     | 
| 
       25 
     | 
    
         
            -
                          'TopicArn' => @topic,
         
     | 
| 
       26 
     | 
    
         
            -
                          'SubscribeURL' => 'http://example.com/subscribe'
         
     | 
| 
       27 
     | 
    
         
            -
                        }
         
     | 
| 
       28 
     | 
    
         
            -
                      end
         
     | 
| 
       29 
     | 
    
         
            -
             
     | 
| 
       30 
     | 
    
         
            -
                      def authentic?
         
     | 
| 
       31 
     | 
    
         
            -
                        @authentic
         
     | 
| 
       32 
     | 
    
         
            -
                      end
         
     | 
| 
       33 
     | 
    
         
            -
                    end
         
     | 
| 
       34 
     | 
    
         
            -
                  end
         
     | 
| 
       35 
     | 
    
         
            -
                end
         
     | 
| 
       36 
     | 
    
         
            -
              end
         
     | 
| 
       37 
     | 
    
         
            -
            end
         
     | 
| 
         @@ -1,28 +0,0 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            # frozen_string_literal: true
         
     | 
| 
       2 
     | 
    
         
            -
             
     | 
| 
       3 
     | 
    
         
            -
            require 'aws-sdk-s3'
         
     | 
| 
       4 
     | 
    
         
            -
             
     | 
| 
       5 
     | 
    
         
            -
            module Aws
         
     | 
| 
       6 
     | 
    
         
            -
              module Rails
         
     | 
| 
       7 
     | 
    
         
            -
                module ActionMailbox
         
     | 
| 
       8 
     | 
    
         
            -
                  # @api private
         
     | 
| 
       9 
     | 
    
         
            -
                  class S3Client
         
     | 
| 
       10 
     | 
    
         
            -
                    class << self
         
     | 
| 
       11 
     | 
    
         
            -
                      def client
         
     | 
| 
       12 
     | 
    
         
            -
                        @client ||= build_client
         
     | 
| 
       13 
     | 
    
         
            -
                      end
         
     | 
| 
       14 
     | 
    
         
            -
             
     | 
| 
       15 
     | 
    
         
            -
                      private
         
     | 
| 
       16 
     | 
    
         
            -
             
     | 
| 
       17 
     | 
    
         
            -
                      def build_client
         
     | 
| 
       18 
     | 
    
         
            -
                        client = Aws::S3::Client.new(
         
     | 
| 
       19 
     | 
    
         
            -
                          **::Rails.configuration.action_mailbox.ses.s3_client_options
         
     | 
| 
       20 
     | 
    
         
            -
                        )
         
     | 
| 
       21 
     | 
    
         
            -
                        client.config.user_agent_frameworks << 'aws-sdk-rails'
         
     | 
| 
       22 
     | 
    
         
            -
                        client
         
     | 
| 
       23 
     | 
    
         
            -
                      end
         
     | 
| 
       24 
     | 
    
         
            -
                    end
         
     | 
| 
       25 
     | 
    
         
            -
                  end
         
     | 
| 
       26 
     | 
    
         
            -
                end
         
     | 
| 
       27 
     | 
    
         
            -
              end
         
     | 
| 
       28 
     | 
    
         
            -
            end
         
     | 
| 
         @@ -1,18 +0,0 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            # frozen_string_literal: true
         
     | 
| 
       2 
     | 
    
         
            -
             
     | 
| 
       3 
     | 
    
         
            -
            require 'aws-sdk-sns'
         
     | 
| 
       4 
     | 
    
         
            -
             
     | 
| 
       5 
     | 
    
         
            -
            module Aws
         
     | 
| 
       6 
     | 
    
         
            -
              module Rails
         
     | 
| 
       7 
     | 
    
         
            -
                module ActionMailbox
         
     | 
| 
       8 
     | 
    
         
            -
                  # @api private
         
     | 
| 
       9 
     | 
    
         
            -
                  class SnsMessageVerifier
         
     | 
| 
       10 
     | 
    
         
            -
                    class << self
         
     | 
| 
       11 
     | 
    
         
            -
                      def verifier
         
     | 
| 
       12 
     | 
    
         
            -
                        @verifier ||= Aws::SNS::MessageVerifier.new
         
     | 
| 
       13 
     | 
    
         
            -
                      end
         
     | 
| 
       14 
     | 
    
         
            -
                    end
         
     | 
| 
       15 
     | 
    
         
            -
                  end
         
     | 
| 
       16 
     | 
    
         
            -
                end
         
     | 
| 
       17 
     | 
    
         
            -
              end
         
     | 
| 
       18 
     | 
    
         
            -
            end
         
     | 
| 
         @@ -1,99 +0,0 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            # frozen_string_literal: true
         
     | 
| 
       2 
     | 
    
         
            -
             
     | 
| 
       3 
     | 
    
         
            -
            require 'aws-sdk-sns'
         
     | 
| 
       4 
     | 
    
         
            -
            require 'aws/rails/action_mailbox/s3_client'
         
     | 
| 
       5 
     | 
    
         
            -
            require 'aws/rails/action_mailbox/sns_message_verifier'
         
     | 
| 
       6 
     | 
    
         
            -
             
     | 
| 
       7 
     | 
    
         
            -
            module Aws
         
     | 
| 
       8 
     | 
    
         
            -
              module Rails
         
     | 
| 
       9 
     | 
    
         
            -
                module ActionMailbox
         
     | 
| 
       10 
     | 
    
         
            -
                  # @api private
         
     | 
| 
       11 
     | 
    
         
            -
                  class SnsNotification
         
     | 
| 
       12 
     | 
    
         
            -
                    class MessageContentError < StandardError; end
         
     | 
| 
       13 
     | 
    
         
            -
             
     | 
| 
       14 
     | 
    
         
            -
                    def initialize(request_body)
         
     | 
| 
       15 
     | 
    
         
            -
                      @request_body = request_body
         
     | 
| 
       16 
     | 
    
         
            -
                    end
         
     | 
| 
       17 
     | 
    
         
            -
             
     | 
| 
       18 
     | 
    
         
            -
                    def subscription_confirmed?
         
     | 
| 
       19 
     | 
    
         
            -
                      (200..299).cover?(confirmation_response.code.to_i)
         
     | 
| 
       20 
     | 
    
         
            -
                    end
         
     | 
| 
       21 
     | 
    
         
            -
             
     | 
| 
       22 
     | 
    
         
            -
                    def verified?
         
     | 
| 
       23 
     | 
    
         
            -
                      SnsMessageVerifier.verifier.authentic?(@request_body)
         
     | 
| 
       24 
     | 
    
         
            -
                    end
         
     | 
| 
       25 
     | 
    
         
            -
             
     | 
| 
       26 
     | 
    
         
            -
                    def topic
         
     | 
| 
       27 
     | 
    
         
            -
                      notification.fetch(:TopicArn)
         
     | 
| 
       28 
     | 
    
         
            -
                    end
         
     | 
| 
       29 
     | 
    
         
            -
             
     | 
| 
       30 
     | 
    
         
            -
                    def type
         
     | 
| 
       31 
     | 
    
         
            -
                      notification.fetch(:Type)
         
     | 
| 
       32 
     | 
    
         
            -
                    end
         
     | 
| 
       33 
     | 
    
         
            -
             
     | 
| 
       34 
     | 
    
         
            -
                    def message_content
         
     | 
| 
       35 
     | 
    
         
            -
                      raise MessageContentError, 'Incoming emails must have notificationType `Received`' unless receipt?
         
     | 
| 
       36 
     | 
    
         
            -
             
     | 
| 
       37 
     | 
    
         
            -
                      if content_in_s3?
         
     | 
| 
       38 
     | 
    
         
            -
                        s3_content
         
     | 
| 
       39 
     | 
    
         
            -
                      else
         
     | 
| 
       40 
     | 
    
         
            -
                        return message[:content] unless destination
         
     | 
| 
       41 
     | 
    
         
            -
             
     | 
| 
       42 
     | 
    
         
            -
                        "X-Original-To: #{destination}\n#{message[:content]}"
         
     | 
| 
       43 
     | 
    
         
            -
                      end
         
     | 
| 
       44 
     | 
    
         
            -
                    end
         
     | 
| 
       45 
     | 
    
         
            -
             
     | 
| 
       46 
     | 
    
         
            -
                    private
         
     | 
| 
       47 
     | 
    
         
            -
             
     | 
| 
       48 
     | 
    
         
            -
                    def notification
         
     | 
| 
       49 
     | 
    
         
            -
                      @notification ||= JSON.parse(@request_body, symbolize_names: true)
         
     | 
| 
       50 
     | 
    
         
            -
                    rescue JSON::ParserError => e
         
     | 
| 
       51 
     | 
    
         
            -
                      Rails.logger.warn("Unable to parse SNS notification: #{e}")
         
     | 
| 
       52 
     | 
    
         
            -
                      nil
         
     | 
| 
       53 
     | 
    
         
            -
                    end
         
     | 
| 
       54 
     | 
    
         
            -
             
     | 
| 
       55 
     | 
    
         
            -
                    def s3_content
         
     | 
| 
       56 
     | 
    
         
            -
                      S3Client
         
     | 
| 
       57 
     | 
    
         
            -
                        .client
         
     | 
| 
       58 
     | 
    
         
            -
                        .get_object(key: key, bucket: bucket)
         
     | 
| 
       59 
     | 
    
         
            -
                        .body
         
     | 
| 
       60 
     | 
    
         
            -
                        .string
         
     | 
| 
       61 
     | 
    
         
            -
                    end
         
     | 
| 
       62 
     | 
    
         
            -
             
     | 
| 
       63 
     | 
    
         
            -
                    def message
         
     | 
| 
       64 
     | 
    
         
            -
                      @message ||= JSON.parse(notification[:Message], symbolize_names: true)
         
     | 
| 
       65 
     | 
    
         
            -
                    end
         
     | 
| 
       66 
     | 
    
         
            -
             
     | 
| 
       67 
     | 
    
         
            -
                    def destination
         
     | 
| 
       68 
     | 
    
         
            -
                      message.dig(:mail, :destination)&.first
         
     | 
| 
       69 
     | 
    
         
            -
                    end
         
     | 
| 
       70 
     | 
    
         
            -
             
     | 
| 
       71 
     | 
    
         
            -
                    def action
         
     | 
| 
       72 
     | 
    
         
            -
                      return unless message[:receipt]
         
     | 
| 
       73 
     | 
    
         
            -
             
     | 
| 
       74 
     | 
    
         
            -
                      message.fetch(:receipt).fetch(:action)
         
     | 
| 
       75 
     | 
    
         
            -
                    end
         
     | 
| 
       76 
     | 
    
         
            -
             
     | 
| 
       77 
     | 
    
         
            -
                    def bucket
         
     | 
| 
       78 
     | 
    
         
            -
                      action.fetch(:bucketName)
         
     | 
| 
       79 
     | 
    
         
            -
                    end
         
     | 
| 
       80 
     | 
    
         
            -
             
     | 
| 
       81 
     | 
    
         
            -
                    def key
         
     | 
| 
       82 
     | 
    
         
            -
                      action.fetch(:objectKey)
         
     | 
| 
       83 
     | 
    
         
            -
                    end
         
     | 
| 
       84 
     | 
    
         
            -
             
     | 
| 
       85 
     | 
    
         
            -
                    def content_in_s3?
         
     | 
| 
       86 
     | 
    
         
            -
                      action&.fetch(:type) == 'S3'
         
     | 
| 
       87 
     | 
    
         
            -
                    end
         
     | 
| 
       88 
     | 
    
         
            -
             
     | 
| 
       89 
     | 
    
         
            -
                    def receipt?
         
     | 
| 
       90 
     | 
    
         
            -
                      message.fetch(:notificationType) == 'Received'
         
     | 
| 
       91 
     | 
    
         
            -
                    end
         
     | 
| 
       92 
     | 
    
         
            -
             
     | 
| 
       93 
     | 
    
         
            -
                    def confirmation_response
         
     | 
| 
       94 
     | 
    
         
            -
                      @confirmation_response ||= Net::HTTP.get_response(URI(notification[:SubscribeURL]))
         
     | 
| 
       95 
     | 
    
         
            -
                    end
         
     | 
| 
       96 
     | 
    
         
            -
                  end
         
     | 
| 
       97 
     | 
    
         
            -
                end
         
     | 
| 
       98 
     | 
    
         
            -
              end
         
     | 
| 
       99 
     | 
    
         
            -
            end
         
     | 
| 
         @@ -1,118 +0,0 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            # frozen_string_literal: true
         
     | 
| 
       2 
     | 
    
         
            -
             
     | 
| 
       3 
     | 
    
         
            -
            module Aws
         
     | 
| 
       4 
     | 
    
         
            -
              module Rails
         
     | 
| 
       5 
     | 
    
         
            -
                # Middleware to handle requests from the SQS Daemon present on Elastic Beanstalk worker environments.
         
     | 
| 
       6 
     | 
    
         
            -
                class EbsSqsActiveJobMiddleware
         
     | 
| 
       7 
     | 
    
         
            -
                  INTERNAL_ERROR_MESSAGE = 'Failed to execute job - see Rails log for more details.'
         
     | 
| 
       8 
     | 
    
         
            -
                  INTERNAL_ERROR_RESPONSE = [500, { 'Content-Type' => 'text/plain' }, [INTERNAL_ERROR_MESSAGE]].freeze
         
     | 
| 
       9 
     | 
    
         
            -
                  FORBIDDEN_MESSAGE = 'Request with aws-sqsd user agent was made from untrusted address.'
         
     | 
| 
       10 
     | 
    
         
            -
                  FORBIDDEN_RESPONSE = [403, { 'Content-Type' => 'text/plain' }, [FORBIDDEN_MESSAGE]].freeze
         
     | 
| 
       11 
     | 
    
         
            -
             
     | 
| 
       12 
     | 
    
         
            -
                  def initialize(app)
         
     | 
| 
       13 
     | 
    
         
            -
                    @app = app
         
     | 
| 
       14 
     | 
    
         
            -
                    @logger = ::Rails.logger
         
     | 
| 
       15 
     | 
    
         
            -
                  end
         
     | 
| 
       16 
     | 
    
         
            -
             
     | 
| 
       17 
     | 
    
         
            -
                  def call(env)
         
     | 
| 
       18 
     | 
    
         
            -
                    request = ActionDispatch::Request.new(env)
         
     | 
| 
       19 
     | 
    
         
            -
             
     | 
| 
       20 
     | 
    
         
            -
                    # Pass through unless user agent is the SQS Daemon
         
     | 
| 
       21 
     | 
    
         
            -
                    return @app.call(env) unless from_sqs_daemon?(request)
         
     | 
| 
       22 
     | 
    
         
            -
             
     | 
| 
       23 
     | 
    
         
            -
                    @logger.debug('aws-sdk-rails middleware detected call from Elastic Beanstalk SQS Daemon.')
         
     | 
| 
       24 
     | 
    
         
            -
             
     | 
| 
       25 
     | 
    
         
            -
                    # Only accept requests from this user agent if it is from localhost or a docker host in case of forgery.
         
     | 
| 
       26 
     | 
    
         
            -
                    unless request.local? || sent_from_docker_host?(request)
         
     | 
| 
       27 
     | 
    
         
            -
                      @logger.warn("SQSD request detected from untrusted address #{request.ip}; returning 403 forbidden.")
         
     | 
| 
       28 
     | 
    
         
            -
                      return FORBIDDEN_RESPONSE
         
     | 
| 
       29 
     | 
    
         
            -
                    end
         
     | 
| 
       30 
     | 
    
         
            -
             
     | 
| 
       31 
     | 
    
         
            -
                    # Execute job or periodic task based on HTTP request context
         
     | 
| 
       32 
     | 
    
         
            -
                    periodic_task?(request) ? execute_periodic_task(request) : execute_job(request)
         
     | 
| 
       33 
     | 
    
         
            -
                  end
         
     | 
| 
       34 
     | 
    
         
            -
             
     | 
| 
       35 
     | 
    
         
            -
                  private
         
     | 
| 
       36 
     | 
    
         
            -
             
     | 
| 
       37 
     | 
    
         
            -
                  def execute_job(request)
         
     | 
| 
       38 
     | 
    
         
            -
                    # Jobs queued from the Active Job SQS adapter contain the JSON message in the request body.
         
     | 
| 
       39 
     | 
    
         
            -
                    job = Aws::Json.load(request.body.string)
         
     | 
| 
       40 
     | 
    
         
            -
                    job_name = job['job_class']
         
     | 
| 
       41 
     | 
    
         
            -
                    @logger.debug("Executing job: #{job_name}")
         
     | 
| 
       42 
     | 
    
         
            -
             
     | 
| 
       43 
     | 
    
         
            -
                    begin
         
     | 
| 
       44 
     | 
    
         
            -
                      ActiveJob::Base.execute(job)
         
     | 
| 
       45 
     | 
    
         
            -
                    rescue NoMethodError, NameError => e
         
     | 
| 
       46 
     | 
    
         
            -
                      @logger.error("Job #{job_name} could not resolve to a class that inherits from Active Job.")
         
     | 
| 
       47 
     | 
    
         
            -
                      @logger.error("Error: #{e}")
         
     | 
| 
       48 
     | 
    
         
            -
                      return INTERNAL_ERROR_RESPONSE
         
     | 
| 
       49 
     | 
    
         
            -
                    end
         
     | 
| 
       50 
     | 
    
         
            -
             
     | 
| 
       51 
     | 
    
         
            -
                    [200, { 'Content-Type' => 'text/plain' }, ["Successfully ran job #{job_name}."]]
         
     | 
| 
       52 
     | 
    
         
            -
                  end
         
     | 
| 
       53 
     | 
    
         
            -
             
     | 
| 
       54 
     | 
    
         
            -
                  def execute_periodic_task(request)
         
     | 
| 
       55 
     | 
    
         
            -
                    # The beanstalk worker SQS Daemon will add the 'X-Aws-Sqsd-Taskname' for periodic tasks set in cron.yaml.
         
     | 
| 
       56 
     | 
    
         
            -
                    job_name = request.headers['X-Aws-Sqsd-Taskname']
         
     | 
| 
       57 
     | 
    
         
            -
                    @logger.debug("Creating and executing periodic task: #{job_name}")
         
     | 
| 
       58 
     | 
    
         
            -
             
     | 
| 
       59 
     | 
    
         
            -
                    begin
         
     | 
| 
       60 
     | 
    
         
            -
                      job = job_name.constantize.new
         
     | 
| 
       61 
     | 
    
         
            -
                      job.perform_now
         
     | 
| 
       62 
     | 
    
         
            -
                    rescue NoMethodError, NameError => e
         
     | 
| 
       63 
     | 
    
         
            -
                      @logger.error("Periodic task #{job_name} could not resolve to an Active Job class - check the spelling in cron.yaml.")
         
     | 
| 
       64 
     | 
    
         
            -
                      @logger.error("Error: #{e}.")
         
     | 
| 
       65 
     | 
    
         
            -
                      return INTERNAL_ERROR_RESPONSE
         
     | 
| 
       66 
     | 
    
         
            -
                    end
         
     | 
| 
       67 
     | 
    
         
            -
             
     | 
| 
       68 
     | 
    
         
            -
                    [200, { 'Content-Type' => 'text/plain' }, ["Successfully ran periodic task #{job_name}."]]
         
     | 
| 
       69 
     | 
    
         
            -
                  end
         
     | 
| 
       70 
     | 
    
         
            -
             
     | 
| 
       71 
     | 
    
         
            -
                  # The beanstalk worker SQS Daemon sets a specific User-Agent headers that begins with 'aws-sqsd'.
         
     | 
| 
       72 
     | 
    
         
            -
                  def from_sqs_daemon?(request)
         
     | 
| 
       73 
     | 
    
         
            -
                    current_user_agent = request.headers['User-Agent']
         
     | 
| 
       74 
     | 
    
         
            -
             
     | 
| 
       75 
     | 
    
         
            -
                    !current_user_agent.nil? && current_user_agent.start_with?('aws-sqsd')
         
     | 
| 
       76 
     | 
    
         
            -
                  end
         
     | 
| 
       77 
     | 
    
         
            -
             
     | 
| 
       78 
     | 
    
         
            -
                  # The beanstalk worker SQS Daemon will add the custom 'X-Aws-Sqsd-Taskname' header for periodic tasks set in cron.yaml.
         
     | 
| 
       79 
     | 
    
         
            -
                  def periodic_task?(request)
         
     | 
| 
       80 
     | 
    
         
            -
                    !request.headers['X-Aws-Sqsd-Taskname'].nil? && request.headers['X-Aws-Sqsd-Taskname'].present?
         
     | 
| 
       81 
     | 
    
         
            -
                  end
         
     | 
| 
       82 
     | 
    
         
            -
             
     | 
| 
       83 
     | 
    
         
            -
                  def sent_from_docker_host?(request)
         
     | 
| 
       84 
     | 
    
         
            -
                    app_runs_in_docker_container? && default_gw_ips.include?(request.ip)
         
     | 
| 
       85 
     | 
    
         
            -
                  end
         
     | 
| 
       86 
     | 
    
         
            -
             
     | 
| 
       87 
     | 
    
         
            -
                  def app_runs_in_docker_container?
         
     | 
| 
       88 
     | 
    
         
            -
                    @app_runs_in_docker_container ||= in_docker_container_with_cgroup1? || in_docker_container_with_cgroup2?
         
     | 
| 
       89 
     | 
    
         
            -
                  end
         
     | 
| 
       90 
     | 
    
         
            -
             
     | 
| 
       91 
     | 
    
         
            -
                  def in_docker_container_with_cgroup1?
         
     | 
| 
       92 
     | 
    
         
            -
                    File.exist?('/proc/1/cgroup') && File.read('/proc/1/cgroup') =~ %r{/docker/}
         
     | 
| 
       93 
     | 
    
         
            -
                  end
         
     | 
| 
       94 
     | 
    
         
            -
             
     | 
| 
       95 
     | 
    
         
            -
                  def in_docker_container_with_cgroup2?
         
     | 
| 
       96 
     | 
    
         
            -
                    File.exist?('/proc/self/mountinfo') && File.read('/proc/self/mountinfo') =~ %r{/docker/containers/}
         
     | 
| 
       97 
     | 
    
         
            -
                  end
         
     | 
| 
       98 
     | 
    
         
            -
             
     | 
| 
       99 
     | 
    
         
            -
                  def default_gw_ips
         
     | 
| 
       100 
     | 
    
         
            -
                    default_gw_ips = ['172.17.0.1']
         
     | 
| 
       101 
     | 
    
         
            -
             
     | 
| 
       102 
     | 
    
         
            -
                    if File.exist?('/proc/net/route')
         
     | 
| 
       103 
     | 
    
         
            -
                      File.open('/proc/net/route').each_line do |line|
         
     | 
| 
       104 
     | 
    
         
            -
                        fields = line.strip.split
         
     | 
| 
       105 
     | 
    
         
            -
                        next if fields.size != 11
         
     | 
| 
       106 
     | 
    
         
            -
             
     | 
| 
       107 
     | 
    
         
            -
                        # Destination == 0.0.0.0 and Flags & RTF_GATEWAY != 0
         
     | 
| 
       108 
     | 
    
         
            -
                        if fields[1] == '00000000' && (fields[3].hex & 0x2) != 0
         
     | 
| 
       109 
     | 
    
         
            -
                          default_gw_ips << IPAddr.new_ntoh([fields[2].hex].pack('L')).to_s
         
     | 
| 
       110 
     | 
    
         
            -
                        end
         
     | 
| 
       111 
     | 
    
         
            -
                      end
         
     | 
| 
       112 
     | 
    
         
            -
                    end
         
     | 
| 
       113 
     | 
    
         
            -
             
     | 
| 
       114 
     | 
    
         
            -
                    default_gw_ips
         
     | 
| 
       115 
     | 
    
         
            -
                  end
         
     | 
| 
       116 
     | 
    
         
            -
                end
         
     | 
| 
       117 
     | 
    
         
            -
              end
         
     | 
| 
       118 
     | 
    
         
            -
            end
         
     | 
    
        data/lib/aws/rails/ses_mailer.rb
    DELETED
    
    | 
         @@ -1,49 +0,0 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            # frozen_string_literal: true
         
     | 
| 
       2 
     | 
    
         
            -
             
     | 
| 
       3 
     | 
    
         
            -
            require 'aws-sdk-ses'
         
     | 
| 
       4 
     | 
    
         
            -
             
     | 
| 
       5 
     | 
    
         
            -
            module Aws
         
     | 
| 
       6 
     | 
    
         
            -
              module Rails
         
     | 
| 
       7 
     | 
    
         
            -
                # Provides a delivery method for ActionMailer that uses Amazon Simple Email
         
     | 
| 
       8 
     | 
    
         
            -
                # Service.
         
     | 
| 
       9 
     | 
    
         
            -
                #
         
     | 
| 
       10 
     | 
    
         
            -
                # Once you have an SES delivery method you can configure Rails to
         
     | 
| 
       11 
     | 
    
         
            -
                # use this for ActionMailer in your environment configuration
         
     | 
| 
       12 
     | 
    
         
            -
                # (e.g. RAILS_ROOT/config/environments/production.rb)
         
     | 
| 
       13 
     | 
    
         
            -
                #
         
     | 
| 
       14 
     | 
    
         
            -
                #     config.action_mailer.delivery_method = :ses
         
     | 
| 
       15 
     | 
    
         
            -
                #
         
     | 
| 
       16 
     | 
    
         
            -
                # Uses the AWS SDK for Ruby's credential provider chain when creating an SES
         
     | 
| 
       17 
     | 
    
         
            -
                # client instance.
         
     | 
| 
       18 
     | 
    
         
            -
                class SesMailer
         
     | 
| 
       19 
     | 
    
         
            -
                  # @param [Hash] options Passes along initialization options to
         
     | 
| 
       20 
     | 
    
         
            -
                  #   [Aws::SES::Client.new](https://docs.aws.amazon.com/sdk-for-ruby/v3/api/Aws/SES/Client.html#initialize-instance_method).
         
     | 
| 
       21 
     | 
    
         
            -
                  def initialize(options = {})
         
     | 
| 
       22 
     | 
    
         
            -
                    @client = SES::Client.new(options)
         
     | 
| 
       23 
     | 
    
         
            -
                    @client.config.user_agent_frameworks << 'aws-sdk-rails'
         
     | 
| 
       24 
     | 
    
         
            -
                  end
         
     | 
| 
       25 
     | 
    
         
            -
             
     | 
| 
       26 
     | 
    
         
            -
                  # Rails expects this method to exist, and to handle a Mail::Message object
         
     | 
| 
       27 
     | 
    
         
            -
                  # correctly. Called during mail delivery.
         
     | 
| 
       28 
     | 
    
         
            -
                  def deliver!(message)
         
     | 
| 
       29 
     | 
    
         
            -
                    params = {
         
     | 
| 
       30 
     | 
    
         
            -
                      raw_message: { data: message.to_s },
         
     | 
| 
       31 
     | 
    
         
            -
                      source: message.smtp_envelope_from, # defaults to From header
         
     | 
| 
       32 
     | 
    
         
            -
                      destinations: message.smtp_envelope_to # defaults to destinations (To,Cc,Bcc)
         
     | 
| 
       33 
     | 
    
         
            -
                    }
         
     | 
| 
       34 
     | 
    
         
            -
                    @client.send_raw_email(params).tap do |response|
         
     | 
| 
       35 
     | 
    
         
            -
                      message.header[:ses_message_id] = response.message_id
         
     | 
| 
       36 
     | 
    
         
            -
                    end
         
     | 
| 
       37 
     | 
    
         
            -
                  end
         
     | 
| 
       38 
     | 
    
         
            -
             
     | 
| 
       39 
     | 
    
         
            -
                  # ActionMailer expects this method to be present and to return a hash.
         
     | 
| 
       40 
     | 
    
         
            -
                  def settings
         
     | 
| 
       41 
     | 
    
         
            -
                    {}
         
     | 
| 
       42 
     | 
    
         
            -
                  end
         
     | 
| 
       43 
     | 
    
         
            -
                end
         
     | 
| 
       44 
     | 
    
         
            -
              end
         
     | 
| 
       45 
     | 
    
         
            -
            end
         
     | 
| 
       46 
     | 
    
         
            -
             
     | 
| 
       47 
     | 
    
         
            -
            # This is for backwards compatibility after introducing support for SESv2.
         
     | 
| 
       48 
     | 
    
         
            -
            # The old mailer is now replaced with the new SES (v1) mailer.
         
     | 
| 
       49 
     | 
    
         
            -
            Aws::Rails::Mailer = Aws::Rails::SesMailer
         
     | 
| 
         @@ -1,60 +0,0 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            # frozen_string_literal: true
         
     | 
| 
       2 
     | 
    
         
            -
             
     | 
| 
       3 
     | 
    
         
            -
            require 'aws-sdk-sesv2'
         
     | 
| 
       4 
     | 
    
         
            -
             
     | 
| 
       5 
     | 
    
         
            -
            module Aws
         
     | 
| 
       6 
     | 
    
         
            -
              module Rails
         
     | 
| 
       7 
     | 
    
         
            -
                # Provides a delivery method for ActionMailer that uses Amazon Simple Email
         
     | 
| 
       8 
     | 
    
         
            -
                # Service V2.
         
     | 
| 
       9 
     | 
    
         
            -
                #
         
     | 
| 
       10 
     | 
    
         
            -
                # Once you have an SESv2 delivery method you can configure Rails to
         
     | 
| 
       11 
     | 
    
         
            -
                # use this for ActionMailer in your environment configuration
         
     | 
| 
       12 
     | 
    
         
            -
                # (e.g. RAILS_ROOT/config/environments/production.rb)
         
     | 
| 
       13 
     | 
    
         
            -
                #
         
     | 
| 
       14 
     | 
    
         
            -
                #     config.action_mailer.delivery_method = :sesv2
         
     | 
| 
       15 
     | 
    
         
            -
                #
         
     | 
| 
       16 
     | 
    
         
            -
                # Uses the AWS SDK for Ruby's credential provider chain when creating an SESV2
         
     | 
| 
       17 
     | 
    
         
            -
                # client instance.
         
     | 
| 
       18 
     | 
    
         
            -
                class Sesv2Mailer
         
     | 
| 
       19 
     | 
    
         
            -
                  # @param [Hash] options Passes along initialization options to
         
     | 
| 
       20 
     | 
    
         
            -
                  #   [Aws::SESV2::Client.new](https://docs.aws.amazon.com/sdk-for-ruby/v3/api/Aws/SESV2/Client.html#initialize-instance_method).
         
     | 
| 
       21 
     | 
    
         
            -
                  def initialize(options = {})
         
     | 
| 
       22 
     | 
    
         
            -
                    @client = SESV2::Client.new(options)
         
     | 
| 
       23 
     | 
    
         
            -
                    @client.config.user_agent_frameworks << 'aws-sdk-rails'
         
     | 
| 
       24 
     | 
    
         
            -
                  end
         
     | 
| 
       25 
     | 
    
         
            -
             
     | 
| 
       26 
     | 
    
         
            -
                  # Rails expects this method to exist, and to handle a Mail::Message object
         
     | 
| 
       27 
     | 
    
         
            -
                  # correctly. Called during mail delivery.
         
     | 
| 
       28 
     | 
    
         
            -
                  def deliver!(message)
         
     | 
| 
       29 
     | 
    
         
            -
                    params = { content: { raw: { data: message.to_s } } }
         
     | 
| 
       30 
     | 
    
         
            -
                    # smtp_envelope_from will default to the From address *without* sender names.
         
     | 
| 
       31 
     | 
    
         
            -
                    # By omitting this param, SESv2 will correctly use sender names from the mail headers.
         
     | 
| 
       32 
     | 
    
         
            -
                    # We should only use smtp_envelope_from when it was explicitly set (instance variable set)
         
     | 
| 
       33 
     | 
    
         
            -
                    params[:from_email_address] = message.smtp_envelope_from if message.instance_variable_get(:@smtp_envelope_from)
         
     | 
| 
       34 
     | 
    
         
            -
                    params[:destination] = {
         
     | 
| 
       35 
     | 
    
         
            -
                      to_addresses: to_addresses(message),
         
     | 
| 
       36 
     | 
    
         
            -
                      cc_addresses: message.cc,
         
     | 
| 
       37 
     | 
    
         
            -
                      bcc_addresses: message.bcc
         
     | 
| 
       38 
     | 
    
         
            -
                    }
         
     | 
| 
       39 
     | 
    
         
            -
             
     | 
| 
       40 
     | 
    
         
            -
                    @client.send_email(params).tap do |response|
         
     | 
| 
       41 
     | 
    
         
            -
                      message.header[:ses_message_id] = response.message_id
         
     | 
| 
       42 
     | 
    
         
            -
                    end
         
     | 
| 
       43 
     | 
    
         
            -
                  end
         
     | 
| 
       44 
     | 
    
         
            -
             
     | 
| 
       45 
     | 
    
         
            -
                  # ActionMailer expects this method to be present and to return a hash.
         
     | 
| 
       46 
     | 
    
         
            -
                  def settings
         
     | 
| 
       47 
     | 
    
         
            -
                    {}
         
     | 
| 
       48 
     | 
    
         
            -
                  end
         
     | 
| 
       49 
     | 
    
         
            -
             
     | 
| 
       50 
     | 
    
         
            -
                  private
         
     | 
| 
       51 
     | 
    
         
            -
             
     | 
| 
       52 
     | 
    
         
            -
                  # smtp_envelope_to will default to the full destinations (To, Cc, Bcc)
         
     | 
| 
       53 
     | 
    
         
            -
                  # SES v2 API prefers each component split out into a destination hash.
         
     | 
| 
       54 
     | 
    
         
            -
                  # When smtp_envelope_to was set, use it explicitly for to_address only.
         
     | 
| 
       55 
     | 
    
         
            -
                  def to_addresses(message)
         
     | 
| 
       56 
     | 
    
         
            -
                    message.instance_variable_get(:@smtp_envelope_to) ? message.smtp_envelope_to : message.to
         
     | 
| 
       57 
     | 
    
         
            -
                  end
         
     | 
| 
       58 
     | 
    
         
            -
                end
         
     | 
| 
       59 
     | 
    
         
            -
              end
         
     | 
| 
       60 
     | 
    
         
            -
            end
         
     | 
| 
         @@ -1,184 +0,0 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            # frozen_string_literal: true
         
     | 
| 
       2 
     | 
    
         
            -
             
     | 
| 
       3 
     | 
    
         
            -
            module Aws
         
     | 
| 
       4 
     | 
    
         
            -
              module Rails
         
     | 
| 
       5 
     | 
    
         
            -
                # Configuration for AWS SQS ActiveJob.
         
     | 
| 
       6 
     | 
    
         
            -
                module SqsActiveJob
         
     | 
| 
       7 
     | 
    
         
            -
                  # Use +Aws::Rails::SqsActiveJob.config+ to access the singleton config instance.
         
     | 
| 
       8 
     | 
    
         
            -
                  class Configuration
         
     | 
| 
       9 
     | 
    
         
            -
                    # Default configuration options
         
     | 
| 
       10 
     | 
    
         
            -
                    # @api private
         
     | 
| 
       11 
     | 
    
         
            -
                    DEFAULTS = {
         
     | 
| 
       12 
     | 
    
         
            -
                      max_messages: 10,
         
     | 
| 
       13 
     | 
    
         
            -
                      shutdown_timeout: 15,
         
     | 
| 
       14 
     | 
    
         
            -
                      retry_standard_errors: true, # TODO: Remove in next MV
         
     | 
| 
       15 
     | 
    
         
            -
                      queues: {},
         
     | 
| 
       16 
     | 
    
         
            -
                      logger: ::Rails.logger,
         
     | 
| 
       17 
     | 
    
         
            -
                      message_group_id: 'SqsActiveJobGroup',
         
     | 
| 
       18 
     | 
    
         
            -
                      excluded_deduplication_keys: ['job_id']
         
     | 
| 
       19 
     | 
    
         
            -
                    }.freeze
         
     | 
| 
       20 
     | 
    
         
            -
             
     | 
| 
       21 
     | 
    
         
            -
                    # @api private
         
     | 
| 
       22 
     | 
    
         
            -
                    attr_accessor :queues, :max_messages, :visibility_timeout,
         
     | 
| 
       23 
     | 
    
         
            -
                                  :shutdown_timeout, :client, :logger,
         
     | 
| 
       24 
     | 
    
         
            -
                                  :async_queue_error_handler, :message_group_id
         
     | 
| 
       25 
     | 
    
         
            -
             
     | 
| 
       26 
     | 
    
         
            -
                    attr_reader :excluded_deduplication_keys
         
     | 
| 
       27 
     | 
    
         
            -
             
     | 
| 
       28 
     | 
    
         
            -
                    # Don't use this method directly: Configuration is a singleton class, use
         
     | 
| 
       29 
     | 
    
         
            -
                    # +Aws::Rails::SqsActiveJob.config+ to access the singleton config.
         
     | 
| 
       30 
     | 
    
         
            -
                    #
         
     | 
| 
       31 
     | 
    
         
            -
                    # @param [Hash] options
         
     | 
| 
       32 
     | 
    
         
            -
                    # @option options [Hash[Symbol, String]] :queues A mapping between the
         
     | 
| 
       33 
     | 
    
         
            -
                    #   active job queue name and the SQS Queue URL. Note: multiple active
         
     | 
| 
       34 
     | 
    
         
            -
                    #   job queues can map to the same SQS Queue URL.
         
     | 
| 
       35 
     | 
    
         
            -
                    #
         
     | 
| 
       36 
     | 
    
         
            -
                    # @option options  [Integer] :max_messages
         
     | 
| 
       37 
     | 
    
         
            -
                    #    The max number of messages to poll for in a batch.
         
     | 
| 
       38 
     | 
    
         
            -
                    #
         
     | 
| 
       39 
     | 
    
         
            -
                    # @option options [Integer] :visibility_timeout
         
     | 
| 
       40 
     | 
    
         
            -
                    #   If unset, the visibility timeout configured on the
         
     | 
| 
       41 
     | 
    
         
            -
                    #   SQS queue will be used.
         
     | 
| 
       42 
     | 
    
         
            -
                    #   The visibility timeout is the number of seconds
         
     | 
| 
       43 
     | 
    
         
            -
                    #   that a message will not be processable by any other consumers.
         
     | 
| 
       44 
     | 
    
         
            -
                    #   You should set this value to be longer than your expected job runtime
         
     | 
| 
       45 
     | 
    
         
            -
                    #   to prevent other processes from picking up an running job.
         
     | 
| 
       46 
     | 
    
         
            -
                    #   See the (SQS Visibility Timeout Documentation)[https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/sqs-visibility-timeout.html]
         
     | 
| 
       47 
     | 
    
         
            -
                    #
         
     | 
| 
       48 
     | 
    
         
            -
                    # @option options [Integer] :shutdown_timeout
         
     | 
| 
       49 
     | 
    
         
            -
                    #   the amount of time to wait
         
     | 
| 
       50 
     | 
    
         
            -
                    #   for a clean shutdown.  Jobs that are unable to complete in this time
         
     | 
| 
       51 
     | 
    
         
            -
                    #   will not be deleted from the SQS queue and will be retryable after
         
     | 
| 
       52 
     | 
    
         
            -
                    #   the visibility timeout.
         
     | 
| 
       53 
     | 
    
         
            -
                    #
         
     | 
| 
       54 
     | 
    
         
            -
                    # @ option options [Boolean] :retry_standard_errors
         
     | 
| 
       55 
     | 
    
         
            -
                    #   If `true`, StandardErrors raised by ActiveJobs are left on the queue
         
     | 
| 
       56 
     | 
    
         
            -
                    #   and will be retried (pending the SQS Queue's redrive/DLQ/maximum receive settings).
         
     | 
| 
       57 
     | 
    
         
            -
                    #   This behavior overrides the standard Rails ActiveJob
         
     | 
| 
       58 
     | 
    
         
            -
                    #   [Retry/Discard for failed jobs](https://guides.rubyonrails.org/active_job_basics.html#retrying-or-discarding-failed-jobs)
         
     | 
| 
       59 
     | 
    
         
            -
                    #   behavior.  When set to `true` the retries provided by this will be
         
     | 
| 
       60 
     | 
    
         
            -
                    #   on top of any retries configured on the job with `retry_on`.
         
     | 
| 
       61 
     | 
    
         
            -
                    #   When `false`, retry behavior is fully configured
         
     | 
| 
       62 
     | 
    
         
            -
                    #   through `retry_on`/`discard_on` on the ActiveJobs.
         
     | 
| 
       63 
     | 
    
         
            -
                    #
         
     | 
| 
       64 
     | 
    
         
            -
                    # @option options [ActiveSupport::Logger] :logger Logger to use
         
     | 
| 
       65 
     | 
    
         
            -
                    #   for the poller.
         
     | 
| 
       66 
     | 
    
         
            -
                    #
         
     | 
| 
       67 
     | 
    
         
            -
                    # @option options [String] :config_file
         
     | 
| 
       68 
     | 
    
         
            -
                    #   Override file to load configuration from. If not specified will
         
     | 
| 
       69 
     | 
    
         
            -
                    #   attempt to load from config/aws_sqs_active_job.yml.
         
     | 
| 
       70 
     | 
    
         
            -
                    #
         
     | 
| 
       71 
     | 
    
         
            -
                    # @option options [String] :message_group_id (SqsActiveJobGroup)
         
     | 
| 
       72 
     | 
    
         
            -
                    #  The message_group_id to use for queueing messages on a fifo queues.
         
     | 
| 
       73 
     | 
    
         
            -
                    #  Applies only to jobs queued on FIFO queues.
         
     | 
| 
       74 
     | 
    
         
            -
                    #  See the (SQS FIFO Documentation)[https://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/FIFO-queues.html]
         
     | 
| 
       75 
     | 
    
         
            -
                    #
         
     | 
| 
       76 
     | 
    
         
            -
                    # @option options [Callable] :async_queue_error_handler An error handler
         
     | 
| 
       77 
     | 
    
         
            -
                    #   to be called when the async active job adapter experiances an error
         
     | 
| 
       78 
     | 
    
         
            -
                    #   queueing a job.  Only applies when
         
     | 
| 
       79 
     | 
    
         
            -
                    #   +active_job.queue_adapter = :sqs_async+.  Called with:
         
     | 
| 
       80 
     | 
    
         
            -
                    #   [error, job, job_options]
         
     | 
| 
       81 
     | 
    
         
            -
                    #
         
     | 
| 
       82 
     | 
    
         
            -
                    # @option options [SQS::Client] :client SQS Client to use. A default
         
     | 
| 
       83 
     | 
    
         
            -
                    #   client will be created if none is provided.
         
     | 
| 
       84 
     | 
    
         
            -
                    #
         
     | 
| 
       85 
     | 
    
         
            -
                    # @option options [Array] :excluded_deduplication_keys (['job_id'])
         
     | 
| 
       86 
     | 
    
         
            -
                    #   The type of keys stored in the array should be String or Symbol.
         
     | 
| 
       87 
     | 
    
         
            -
                    #   Using this option, job_id is implicitly added to the keys.
         
     | 
| 
       88 
     | 
    
         
            -
             
     | 
| 
       89 
     | 
    
         
            -
                    def initialize(options = {})
         
     | 
| 
       90 
     | 
    
         
            -
                      options[:config_file] ||= config_file if File.exist?(config_file)
         
     | 
| 
       91 
     | 
    
         
            -
                      options = DEFAULTS
         
     | 
| 
       92 
     | 
    
         
            -
                                .merge(file_options(options))
         
     | 
| 
       93 
     | 
    
         
            -
                                .merge(options)
         
     | 
| 
       94 
     | 
    
         
            -
                      set_attributes(options)
         
     | 
| 
       95 
     | 
    
         
            -
                    end
         
     | 
| 
       96 
     | 
    
         
            -
             
     | 
| 
       97 
     | 
    
         
            -
                    def excluded_deduplication_keys=(keys)
         
     | 
| 
       98 
     | 
    
         
            -
                      @excluded_deduplication_keys = keys.map(&:to_s) | ['job_id']
         
     | 
| 
       99 
     | 
    
         
            -
                    end
         
     | 
| 
       100 
     | 
    
         
            -
             
     | 
| 
       101 
     | 
    
         
            -
                    def client
         
     | 
| 
       102 
     | 
    
         
            -
                      @client ||= begin
         
     | 
| 
       103 
     | 
    
         
            -
                        client = Aws::SQS::Client.new
         
     | 
| 
       104 
     | 
    
         
            -
                        client.config.user_agent_frameworks << 'aws-sdk-rails'
         
     | 
| 
       105 
     | 
    
         
            -
                        client
         
     | 
| 
       106 
     | 
    
         
            -
                      end
         
     | 
| 
       107 
     | 
    
         
            -
                    end
         
     | 
| 
       108 
     | 
    
         
            -
             
     | 
| 
       109 
     | 
    
         
            -
                    # Return the queue_url for a given job_queue name
         
     | 
| 
       110 
     | 
    
         
            -
                    def queue_url_for(job_queue)
         
     | 
| 
       111 
     | 
    
         
            -
                      job_queue = job_queue.to_sym
         
     | 
| 
       112 
     | 
    
         
            -
                      raise ArgumentError, "No queue defined for #{job_queue}" unless queues.key? job_queue
         
     | 
| 
       113 
     | 
    
         
            -
             
     | 
| 
       114 
     | 
    
         
            -
                      queues[job_queue]
         
     | 
| 
       115 
     | 
    
         
            -
                    end
         
     | 
| 
       116 
     | 
    
         
            -
             
     | 
| 
       117 
     | 
    
         
            -
                    # @api private
         
     | 
| 
       118 
     | 
    
         
            -
                    def to_s
         
     | 
| 
       119 
     | 
    
         
            -
                      to_h.to_s
         
     | 
| 
       120 
     | 
    
         
            -
                    end
         
     | 
| 
       121 
     | 
    
         
            -
             
     | 
| 
       122 
     | 
    
         
            -
                    # @api private
         
     | 
| 
       123 
     | 
    
         
            -
                    def to_h
         
     | 
| 
       124 
     | 
    
         
            -
                      h = {}
         
     | 
| 
       125 
     | 
    
         
            -
                      instance_variables.each do |v|
         
     | 
| 
       126 
     | 
    
         
            -
                        v_sym = v.to_s.delete('@').to_sym
         
     | 
| 
       127 
     | 
    
         
            -
                        val = instance_variable_get(v)
         
     | 
| 
       128 
     | 
    
         
            -
                        h[v_sym] = val
         
     | 
| 
       129 
     | 
    
         
            -
                      end
         
     | 
| 
       130 
     | 
    
         
            -
                      h
         
     | 
| 
       131 
     | 
    
         
            -
                    end
         
     | 
| 
       132 
     | 
    
         
            -
             
     | 
| 
       133 
     | 
    
         
            -
                    private
         
     | 
| 
       134 
     | 
    
         
            -
             
     | 
| 
       135 
     | 
    
         
            -
                    # Set accessible attributes after merged options.
         
     | 
| 
       136 
     | 
    
         
            -
                    def set_attributes(options)
         
     | 
| 
       137 
     | 
    
         
            -
                      options.each_key do |opt_name|
         
     | 
| 
       138 
     | 
    
         
            -
                        instance_variable_set("@#{opt_name}", options[opt_name])
         
     | 
| 
       139 
     | 
    
         
            -
                        client.config.user_agent_frameworks << 'aws-sdk-rails' if opt_name == :client
         
     | 
| 
       140 
     | 
    
         
            -
                      end
         
     | 
| 
       141 
     | 
    
         
            -
                    end
         
     | 
| 
       142 
     | 
    
         
            -
             
     | 
| 
       143 
     | 
    
         
            -
                    def file_options(options = {})
         
     | 
| 
       144 
     | 
    
         
            -
                      file_path = config_file_path(options)
         
     | 
| 
       145 
     | 
    
         
            -
                      if file_path
         
     | 
| 
       146 
     | 
    
         
            -
                        load_from_file(file_path)
         
     | 
| 
       147 
     | 
    
         
            -
                      else
         
     | 
| 
       148 
     | 
    
         
            -
                        {}
         
     | 
| 
       149 
     | 
    
         
            -
                      end
         
     | 
| 
       150 
     | 
    
         
            -
                    end
         
     | 
| 
       151 
     | 
    
         
            -
             
     | 
| 
       152 
     | 
    
         
            -
                    def config_file
         
     | 
| 
       153 
     | 
    
         
            -
                      file = ::Rails.root.join("config/aws_sqs_active_job/#{::Rails.env}.yml")
         
     | 
| 
       154 
     | 
    
         
            -
                      file = ::Rails.root.join('config/aws_sqs_active_job.yml') unless File.exist?(file)
         
     | 
| 
       155 
     | 
    
         
            -
                      file
         
     | 
| 
       156 
     | 
    
         
            -
                    end
         
     | 
| 
       157 
     | 
    
         
            -
             
     | 
| 
       158 
     | 
    
         
            -
                    # Load options from YAML file
         
     | 
| 
       159 
     | 
    
         
            -
                    def load_from_file(file_path)
         
     | 
| 
       160 
     | 
    
         
            -
                      opts = load_yaml(file_path) || {}
         
     | 
| 
       161 
     | 
    
         
            -
                      opts.deep_symbolize_keys
         
     | 
| 
       162 
     | 
    
         
            -
                    end
         
     | 
| 
       163 
     | 
    
         
            -
             
     | 
| 
       164 
     | 
    
         
            -
                    # @return [String] Configuration path found in environment or YAML file.
         
     | 
| 
       165 
     | 
    
         
            -
                    def config_file_path(options)
         
     | 
| 
       166 
     | 
    
         
            -
                      options[:config_file] || ENV.fetch('AWS_SQS_ACTIVE_JOB_CONFIG_FILE', nil)
         
     | 
| 
       167 
     | 
    
         
            -
                    end
         
     | 
| 
       168 
     | 
    
         
            -
             
     | 
| 
       169 
     | 
    
         
            -
                    def load_yaml(file_path)
         
     | 
| 
       170 
     | 
    
         
            -
                      require 'erb'
         
     | 
| 
       171 
     | 
    
         
            -
                      source = ERB.new(File.read(file_path)).result
         
     | 
| 
       172 
     | 
    
         
            -
             
     | 
| 
       173 
     | 
    
         
            -
                      # Avoid incompatible changes with Psych 4.0.0
         
     | 
| 
       174 
     | 
    
         
            -
                      # https://bugs.ruby-lang.org/issues/17866
         
     | 
| 
       175 
     | 
    
         
            -
                      begin
         
     | 
| 
       176 
     | 
    
         
            -
                        YAML.safe_load(source, aliases: true) || {}
         
     | 
| 
       177 
     | 
    
         
            -
                      rescue ArgumentError
         
     | 
| 
       178 
     | 
    
         
            -
                        YAML.safe_load(source) || {}
         
     | 
| 
       179 
     | 
    
         
            -
                      end
         
     | 
| 
       180 
     | 
    
         
            -
                    end
         
     | 
| 
       181 
     | 
    
         
            -
                  end
         
     | 
| 
       182 
     | 
    
         
            -
                end
         
     | 
| 
       183 
     | 
    
         
            -
              end
         
     | 
| 
       184 
     | 
    
         
            -
            end
         
     | 
| 
         @@ -1,21 +0,0 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            # frozen_string_literal: true
         
     | 
| 
       2 
     | 
    
         
            -
             
     | 
| 
       3 
     | 
    
         
            -
            module Aws
         
     | 
| 
       4 
     | 
    
         
            -
              module Rails
         
     | 
| 
       5 
     | 
    
         
            -
                # SQS ActiveJob modules
         
     | 
| 
       6 
     | 
    
         
            -
                module SqsActiveJob
         
     | 
| 
       7 
     | 
    
         
            -
                  extend ActiveSupport::Concern
         
     | 
| 
       8 
     | 
    
         
            -
             
     | 
| 
       9 
     | 
    
         
            -
                  included do
         
     | 
| 
       10 
     | 
    
         
            -
                    class_attribute :excluded_deduplication_keys
         
     | 
| 
       11 
     | 
    
         
            -
                  end
         
     | 
| 
       12 
     | 
    
         
            -
             
     | 
| 
       13 
     | 
    
         
            -
                  # class methods for SQS ActiveJob.
         
     | 
| 
       14 
     | 
    
         
            -
                  module ClassMethods
         
     | 
| 
       15 
     | 
    
         
            -
                    def deduplicate_without(*keys)
         
     | 
| 
       16 
     | 
    
         
            -
                      self.excluded_deduplication_keys = keys.map(&:to_s) | ['job_id']
         
     | 
| 
       17 
     | 
    
         
            -
                    end
         
     | 
| 
       18 
     | 
    
         
            -
                  end
         
     | 
| 
       19 
     | 
    
         
            -
                end
         
     | 
| 
       20 
     | 
    
         
            -
              end
         
     | 
| 
       21 
     | 
    
         
            -
            end
         
     | 
| 
         @@ -1,77 +0,0 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            # frozen_string_literal: true
         
     | 
| 
       2 
     | 
    
         
            -
             
     | 
| 
       3 
     | 
    
         
            -
            require 'concurrent'
         
     | 
| 
       4 
     | 
    
         
            -
             
     | 
| 
       5 
     | 
    
         
            -
            module Aws
         
     | 
| 
       6 
     | 
    
         
            -
              module Rails
         
     | 
| 
       7 
     | 
    
         
            -
                module SqsActiveJob
         
     | 
| 
       8 
     | 
    
         
            -
                  # CLI runner for polling for SQS ActiveJobs
         
     | 
| 
       9 
     | 
    
         
            -
                  class Executor
         
     | 
| 
       10 
     | 
    
         
            -
                    DEFAULTS = {
         
     | 
| 
       11 
     | 
    
         
            -
                      min_threads: 0,
         
     | 
| 
       12 
     | 
    
         
            -
                      max_threads: Integer(Concurrent.available_processor_count || Concurrent.processor_count),
         
     | 
| 
       13 
     | 
    
         
            -
                      auto_terminate: true,
         
     | 
| 
       14 
     | 
    
         
            -
                      idletime: 60, # 1 minute
         
     | 
| 
       15 
     | 
    
         
            -
                      fallback_policy: :abort # Concurrent::RejectedExecutionError must be handled
         
     | 
| 
       16 
     | 
    
         
            -
                    }.freeze
         
     | 
| 
       17 
     | 
    
         
            -
             
     | 
| 
       18 
     | 
    
         
            -
                    def initialize(options = {})
         
     | 
| 
       19 
     | 
    
         
            -
                      @executor = Concurrent::ThreadPoolExecutor.new(DEFAULTS.merge(options))
         
     | 
| 
       20 
     | 
    
         
            -
                      @retry_standard_errors = options[:retry_standard_errors]
         
     | 
| 
       21 
     | 
    
         
            -
                      @logger = options[:logger] || ActiveSupport::Logger.new($stdout)
         
     | 
| 
       22 
     | 
    
         
            -
                      @task_complete = Concurrent::Event.new
         
     | 
| 
       23 
     | 
    
         
            -
                    end
         
     | 
| 
       24 
     | 
    
         
            -
             
     | 
| 
       25 
     | 
    
         
            -
                    def execute(message)
         
     | 
| 
       26 
     | 
    
         
            -
                      post_task(message)
         
     | 
| 
       27 
     | 
    
         
            -
                    rescue Concurrent::RejectedExecutionError
         
     | 
| 
       28 
     | 
    
         
            -
                      # no capacity, wait for a task to complete
         
     | 
| 
       29 
     | 
    
         
            -
                      @task_complete.reset
         
     | 
| 
       30 
     | 
    
         
            -
                      @task_complete.wait
         
     | 
| 
       31 
     | 
    
         
            -
                      retry
         
     | 
| 
       32 
     | 
    
         
            -
                    end
         
     | 
| 
       33 
     | 
    
         
            -
             
     | 
| 
       34 
     | 
    
         
            -
                    def shutdown(timeout = nil)
         
     | 
| 
       35 
     | 
    
         
            -
                      @executor.shutdown
         
     | 
| 
       36 
     | 
    
         
            -
                      clean_shutdown = @executor.wait_for_termination(timeout)
         
     | 
| 
       37 
     | 
    
         
            -
                      if clean_shutdown
         
     | 
| 
       38 
     | 
    
         
            -
                        @logger.info 'Clean shutdown complete.  All executing jobs finished.'
         
     | 
| 
       39 
     | 
    
         
            -
                      else
         
     | 
| 
       40 
     | 
    
         
            -
                        @logger.info "Timeout (#{timeout}) exceeded.  Some jobs may not have " \
         
     | 
| 
       41 
     | 
    
         
            -
                                     'finished cleanly.  Unfinished jobs will not be removed from ' \
         
     | 
| 
       42 
     | 
    
         
            -
                                     'the queue and can be ru-run once their visibility timeout ' \
         
     | 
| 
       43 
     | 
    
         
            -
                                     'passes.'
         
     | 
| 
       44 
     | 
    
         
            -
                      end
         
     | 
| 
       45 
     | 
    
         
            -
                    end
         
     | 
| 
       46 
     | 
    
         
            -
             
     | 
| 
       47 
     | 
    
         
            -
                    private
         
     | 
| 
       48 
     | 
    
         
            -
             
     | 
| 
       49 
     | 
    
         
            -
                    def post_task(message)
         
     | 
| 
       50 
     | 
    
         
            -
                      @executor.post(message) do |message|
         
     | 
| 
       51 
     | 
    
         
            -
                        job = JobRunner.new(message)
         
     | 
| 
       52 
     | 
    
         
            -
                        @logger.info("Running job: #{job.id}[#{job.class_name}]")
         
     | 
| 
       53 
     | 
    
         
            -
                        job.run
         
     | 
| 
       54 
     | 
    
         
            -
                        message.delete
         
     | 
| 
       55 
     | 
    
         
            -
                      rescue Aws::Json::ParseError => e
         
     | 
| 
       56 
     | 
    
         
            -
                        @logger.error "Unable to parse message body: #{message.data.body}. Error: #{e}."
         
     | 
| 
       57 
     | 
    
         
            -
                      rescue StandardError => e
         
     | 
| 
       58 
     | 
    
         
            -
                        job_msg = job ? "#{job.id}[#{job.class_name}]" : 'unknown job'
         
     | 
| 
       59 
     | 
    
         
            -
                        @logger.info "Error processing job #{job_msg}: #{e}"
         
     | 
| 
       60 
     | 
    
         
            -
                        @logger.debug e.backtrace.join("\n")
         
     | 
| 
       61 
     | 
    
         
            -
             
     | 
| 
       62 
     | 
    
         
            -
                        if @retry_standard_errors && !job.exception_executions?
         
     | 
| 
       63 
     | 
    
         
            -
                          @logger.info(
         
     | 
| 
       64 
     | 
    
         
            -
                            'retry_standard_errors is enabled and job has not ' \
         
     | 
| 
       65 
     | 
    
         
            -
                            "been retried by Rails.  Leaving #{job_msg} in the queue."
         
     | 
| 
       66 
     | 
    
         
            -
                          )
         
     | 
| 
       67 
     | 
    
         
            -
                        else
         
     | 
| 
       68 
     | 
    
         
            -
                          message.delete
         
     | 
| 
       69 
     | 
    
         
            -
                        end
         
     | 
| 
       70 
     | 
    
         
            -
                      ensure
         
     | 
| 
       71 
     | 
    
         
            -
                        @task_complete.set
         
     | 
| 
       72 
     | 
    
         
            -
                      end
         
     | 
| 
       73 
     | 
    
         
            -
                    end
         
     | 
| 
       74 
     | 
    
         
            -
                  end
         
     | 
| 
       75 
     | 
    
         
            -
                end
         
     | 
| 
       76 
     | 
    
         
            -
              end
         
     | 
| 
       77 
     | 
    
         
            -
            end
         
     |