aws-sdk-core 3.90.1 → 3.91.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/VERSION +1 -1
 - data/lib/aws-sdk-core/credential_provider_chain.rb +5 -1
 - data/lib/aws-sdk-core/errors.rb +19 -0
 - data/lib/aws-sdk-core/plugins/client_metrics_plugin.rb +2 -1
 - data/lib/aws-sdk-core/plugins/retries/client_rate_limiter.rb +137 -0
 - data/lib/aws-sdk-core/plugins/retries/clock_skew.rb +63 -0
 - data/lib/aws-sdk-core/plugins/retries/error_inspector.rb +142 -0
 - data/lib/aws-sdk-core/plugins/retries/retry_quota.rb +57 -0
 - data/lib/aws-sdk-core/plugins/retry_errors.rb +252 -112
 - data/lib/aws-sdk-core/plugins/signature_v4.rb +13 -2
 - data/lib/aws-sdk-core/plugins/stub_responses.rb +1 -0
 - data/lib/aws-sdk-core/shared_config.rb +8 -4
 - data/lib/aws-sdk-core/util.rb +4 -0
 - data/lib/aws-sdk-sts.rb +7 -4
 - data/lib/aws-sdk-sts/client.rb +61 -10
 - data/lib/aws-sdk-sts/errors.rb +30 -8
 - data/lib/aws-sdk-sts/resource.rb +7 -0
 - data/lib/seahorse/client/response.rb +3 -5
 - metadata +6 -2
 
    
        checksums.yaml
    CHANGED
    
    | 
         @@ -1,7 +1,7 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            ---
         
     | 
| 
       2 
2 
     | 
    
         
             
            SHA1:
         
     | 
| 
       3 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       4 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 3 
     | 
    
         
            +
              metadata.gz: '018176486b2589c3e5643f0517d600048b788239'
         
     | 
| 
      
 4 
     | 
    
         
            +
              data.tar.gz: bf23afa4bc903911cc3a571b318eb38911a4cb62
         
     | 
| 
       5 
5 
     | 
    
         
             
            SHA512:
         
     | 
| 
       6 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       7 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 6 
     | 
    
         
            +
              metadata.gz: 8c5827b6dfca9a435419df7ec67f006179fe4656e909769e7545dbd4803b6723bdfedc7a9e89f23bff052d3e93428dcd39c9b803a1f35aba3ac26cfc3c33fb87
         
     | 
| 
      
 7 
     | 
    
         
            +
              data.tar.gz: a244072123870020dbca0dee7bbe8f7057367b1ce81e18c7078b994e79a5f48c5ca5639e0df4113d4e68fdbc12627097751d21e45a65c4359e7d0abd4a548474
         
     | 
    
        data/VERSION
    CHANGED
    
    | 
         @@ -1 +1 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            3. 
     | 
| 
      
 1 
     | 
    
         
            +
            3.91.0
         
     | 
| 
         @@ -28,7 +28,11 @@ module Aws 
     | 
|
| 
       28 
28 
     | 
    
         
             
                    [:assume_role_credentials, {}],
         
     | 
| 
       29 
29 
     | 
    
         
             
                    [:shared_credentials, {}],
         
     | 
| 
       30 
30 
     | 
    
         
             
                    [:process_credentials, {}],
         
     | 
| 
       31 
     | 
    
         
            -
                    [:instance_profile_credentials, { 
     | 
| 
      
 31 
     | 
    
         
            +
                    [:instance_profile_credentials, {
         
     | 
| 
      
 32 
     | 
    
         
            +
                      retries: @config ? @config.instance_profile_credentials_retries : 0,
         
     | 
| 
      
 33 
     | 
    
         
            +
                      http_open_timeout: @config ? @config.instance_profile_credentials_timeout : 1,
         
     | 
| 
      
 34 
     | 
    
         
            +
                      http_read_timeout: @config ? @config.instance_profile_credentials_timeout : 1
         
     | 
| 
      
 35 
     | 
    
         
            +
                    }]
         
     | 
| 
       32 
36 
     | 
    
         
             
                  ]
         
     | 
| 
       33 
37 
     | 
    
         
             
                end
         
     | 
| 
       34 
38 
     | 
    
         | 
    
        data/lib/aws-sdk-core/errors.rb
    CHANGED
    
    | 
         @@ -36,6 +36,16 @@ module Aws 
     | 
|
| 
       36 
36 
     | 
    
         
             
                    attr_accessor :code
         
     | 
| 
       37 
37 
     | 
    
         | 
| 
       38 
38 
     | 
    
         
             
                  end
         
     | 
| 
      
 39 
     | 
    
         
            +
             
     | 
| 
      
 40 
     | 
    
         
            +
                  # @api private undocumented
         
     | 
| 
      
 41 
     | 
    
         
            +
                  def retryable?
         
     | 
| 
      
 42 
     | 
    
         
            +
                    false
         
     | 
| 
      
 43 
     | 
    
         
            +
                  end
         
     | 
| 
      
 44 
     | 
    
         
            +
             
     | 
| 
      
 45 
     | 
    
         
            +
                  # @api private undocumented
         
     | 
| 
      
 46 
     | 
    
         
            +
                  def throttling?
         
     | 
| 
      
 47 
     | 
    
         
            +
                    false
         
     | 
| 
      
 48 
     | 
    
         
            +
                  end
         
     | 
| 
       39 
49 
     | 
    
         
             
                end
         
     | 
| 
       40 
50 
     | 
    
         | 
| 
       41 
51 
     | 
    
         
             
                # Raised when InstanceProfileCredentialsProvider or
         
     | 
| 
         @@ -255,6 +265,15 @@ Known AWS regions include (not specific to this service): 
     | 
|
| 
       255 
265 
     | 
    
         | 
| 
       256 
266 
     | 
    
         
             
                end
         
     | 
| 
       257 
267 
     | 
    
         | 
| 
      
 268 
     | 
    
         
            +
                # Raised when attempting to retry a request
         
     | 
| 
      
 269 
     | 
    
         
            +
                # and no capacity is available to retry (See adaptive retry_mode)
         
     | 
| 
      
 270 
     | 
    
         
            +
                class RetryCapacityNotAvailableError < RuntimeError
         
     | 
| 
      
 271 
     | 
    
         
            +
                  def initialize(*args)
         
     | 
| 
      
 272 
     | 
    
         
            +
                    msg = 'Insufficient client side capacity available to retry request.'
         
     | 
| 
      
 273 
     | 
    
         
            +
                    super(msg)
         
     | 
| 
      
 274 
     | 
    
         
            +
                  end
         
     | 
| 
      
 275 
     | 
    
         
            +
                end
         
     | 
| 
      
 276 
     | 
    
         
            +
             
     | 
| 
       258 
277 
     | 
    
         
             
                # This module is mixed into another module, providing dynamic
         
     | 
| 
       259 
278 
     | 
    
         
             
                # error classes.  Error classes all inherit from {ServiceError}.
         
     | 
| 
       260 
279 
     | 
    
         
             
                #
         
     | 
| 
         @@ -1,4 +1,5 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            require 'date'
         
     | 
| 
      
 2 
     | 
    
         
            +
            require_relative 'retries/error_inspector'
         
     | 
| 
       2 
3 
     | 
    
         | 
| 
       3 
4 
     | 
    
         
             
            module Aws
         
     | 
| 
       4 
5 
     | 
    
         
             
              module Plugins
         
     | 
| 
         @@ -141,7 +142,7 @@ all generated client side metrics. Defaults to an empty string. 
     | 
|
| 
       141 
142 
     | 
    
         
             
                        @handler.call(context)
         
     | 
| 
       142 
143 
     | 
    
         
             
                      rescue StandardError => e
         
     | 
| 
       143 
144 
     | 
    
         
             
                        # Handle SDK Exceptions
         
     | 
| 
       144 
     | 
    
         
            -
                        inspector =  
     | 
| 
      
 145 
     | 
    
         
            +
                        inspector = Retries::ErrorInspector.new(
         
     | 
| 
       145 
146 
     | 
    
         
             
                          e,
         
     | 
| 
       146 
147 
     | 
    
         
             
                          context.http_response.status_code
         
     | 
| 
       147 
148 
     | 
    
         
             
                        )
         
     | 
| 
         @@ -0,0 +1,137 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Aws
         
     | 
| 
      
 2 
     | 
    
         
            +
              module Plugins
         
     | 
| 
      
 3 
     | 
    
         
            +
                module Retries
         
     | 
| 
      
 4 
     | 
    
         
            +
                  # @api private
         
     | 
| 
      
 5 
     | 
    
         
            +
                  # Used only in 'adaptive' retry mode
         
     | 
| 
      
 6 
     | 
    
         
            +
                  class ClientRateLimiter
         
     | 
| 
      
 7 
     | 
    
         
            +
                    MIN_CAPACITY = 1
         
     | 
| 
      
 8 
     | 
    
         
            +
                    MIN_FILL_RATE = 0.5
         
     | 
| 
      
 9 
     | 
    
         
            +
                    SMOOTH = 0.8
         
     | 
| 
      
 10 
     | 
    
         
            +
                    # How much to scale back after a throttling response
         
     | 
| 
      
 11 
     | 
    
         
            +
                    BETA = 0.7
         
     | 
| 
      
 12 
     | 
    
         
            +
                    # Controls how aggressively we scale up after being throttled
         
     | 
| 
      
 13 
     | 
    
         
            +
                    SCALE_CONSTANT = 0.4
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                    def initialize
         
     | 
| 
      
 16 
     | 
    
         
            +
                      @mutex                = Mutex.new
         
     | 
| 
      
 17 
     | 
    
         
            +
                      @fill_rate            = nil
         
     | 
| 
      
 18 
     | 
    
         
            +
                      @max_capacity         = nil
         
     | 
| 
      
 19 
     | 
    
         
            +
                      @current_capacity     = 0
         
     | 
| 
      
 20 
     | 
    
         
            +
                      @last_timestamp       = nil
         
     | 
| 
      
 21 
     | 
    
         
            +
                      @enabled              = false
         
     | 
| 
      
 22 
     | 
    
         
            +
                      @measured_tx_rate     = 0
         
     | 
| 
      
 23 
     | 
    
         
            +
                      @last_tx_rate_bucket  = Aws::Util.monotonic_seconds
         
     | 
| 
      
 24 
     | 
    
         
            +
                      @request_count        = 0
         
     | 
| 
      
 25 
     | 
    
         
            +
                      @last_max_rate        = 0
         
     | 
| 
      
 26 
     | 
    
         
            +
                      @last_throttle_time   = Aws::Util.monotonic_seconds
         
     | 
| 
      
 27 
     | 
    
         
            +
                      @calculated_rate      = nil
         
     | 
| 
      
 28 
     | 
    
         
            +
                    end
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
                    def token_bucket_acquire(amount, wait_to_fill = true)
         
     | 
| 
      
 31 
     | 
    
         
            +
                      # Client side throttling is not enabled until we see a
         
     | 
| 
      
 32 
     | 
    
         
            +
                      # throttling error
         
     | 
| 
      
 33 
     | 
    
         
            +
                      return unless @enabled
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
                      @mutex.synchronize do
         
     | 
| 
      
 36 
     | 
    
         
            +
                        token_bucket_refill
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
      
 38 
     | 
    
         
            +
                        # Next see if we have enough capacity for the requested amount
         
     | 
| 
      
 39 
     | 
    
         
            +
                        while @current_capacity < amount
         
     | 
| 
      
 40 
     | 
    
         
            +
                          raise Aws::Errors::RetryCapacityNotAvailableError unless wait_to_fill
         
     | 
| 
      
 41 
     | 
    
         
            +
                          @mutex.sleep((amount - @current_capacity) / @fill_rate)
         
     | 
| 
      
 42 
     | 
    
         
            +
                          token_bucket_refill
         
     | 
| 
      
 43 
     | 
    
         
            +
                        end
         
     | 
| 
      
 44 
     | 
    
         
            +
                        @current_capacity -= amount
         
     | 
| 
      
 45 
     | 
    
         
            +
                      end
         
     | 
| 
      
 46 
     | 
    
         
            +
                    end
         
     | 
| 
      
 47 
     | 
    
         
            +
             
     | 
| 
      
 48 
     | 
    
         
            +
                    def update_sending_rate(is_throttling_error)
         
     | 
| 
      
 49 
     | 
    
         
            +
                      @mutex.synchronize do
         
     | 
| 
      
 50 
     | 
    
         
            +
                        update_measured_rate
         
     | 
| 
      
 51 
     | 
    
         
            +
             
     | 
| 
      
 52 
     | 
    
         
            +
                        if is_throttling_error
         
     | 
| 
      
 53 
     | 
    
         
            +
                          rate_to_use = if @enabled
         
     | 
| 
      
 54 
     | 
    
         
            +
                                          [@measured_tx_rate, @fill_rate].min
         
     | 
| 
      
 55 
     | 
    
         
            +
                                        else
         
     | 
| 
      
 56 
     | 
    
         
            +
                                          @measured_tx_rate
         
     | 
| 
      
 57 
     | 
    
         
            +
                                        end
         
     | 
| 
      
 58 
     | 
    
         
            +
             
     | 
| 
      
 59 
     | 
    
         
            +
                          # The fill_rate is from the token bucket
         
     | 
| 
      
 60 
     | 
    
         
            +
                          @last_max_rate = rate_to_use
         
     | 
| 
      
 61 
     | 
    
         
            +
                          calculate_time_window
         
     | 
| 
      
 62 
     | 
    
         
            +
                          @last_throttle_time = Aws::Util.monotonic_seconds
         
     | 
| 
      
 63 
     | 
    
         
            +
                          @calculated_rate = cubic_throttle(rate_to_use)
         
     | 
| 
      
 64 
     | 
    
         
            +
                          enable_token_bucket
         
     | 
| 
      
 65 
     | 
    
         
            +
                        else
         
     | 
| 
      
 66 
     | 
    
         
            +
                          calculate_time_window
         
     | 
| 
      
 67 
     | 
    
         
            +
                          @calculated_rate = cubic_success(Aws::Util.monotonic_seconds)
         
     | 
| 
      
 68 
     | 
    
         
            +
                        end
         
     | 
| 
      
 69 
     | 
    
         
            +
             
     | 
| 
      
 70 
     | 
    
         
            +
                        new_rate = [@calculated_rate, 2 * @measured_tx_rate].min
         
     | 
| 
      
 71 
     | 
    
         
            +
                        token_bucket_update_rate(new_rate)
         
     | 
| 
      
 72 
     | 
    
         
            +
                      end
         
     | 
| 
      
 73 
     | 
    
         
            +
                    end
         
     | 
| 
      
 74 
     | 
    
         
            +
             
     | 
| 
      
 75 
     | 
    
         
            +
                    private
         
     | 
| 
      
 76 
     | 
    
         
            +
             
     | 
| 
      
 77 
     | 
    
         
            +
                    def token_bucket_refill
         
     | 
| 
      
 78 
     | 
    
         
            +
                      timestamp = Aws::Util.monotonic_seconds
         
     | 
| 
      
 79 
     | 
    
         
            +
                      unless @last_timestamp
         
     | 
| 
      
 80 
     | 
    
         
            +
                        @last_timestamp = timestamp
         
     | 
| 
      
 81 
     | 
    
         
            +
                        return
         
     | 
| 
      
 82 
     | 
    
         
            +
                      end
         
     | 
| 
      
 83 
     | 
    
         
            +
             
     | 
| 
      
 84 
     | 
    
         
            +
                      fill_amount = (timestamp - @last_timestamp) * @fill_rate
         
     | 
| 
      
 85 
     | 
    
         
            +
                      @current_capacity = [
         
     | 
| 
      
 86 
     | 
    
         
            +
                        @max_capacity, @current_capacity + fill_amount
         
     | 
| 
      
 87 
     | 
    
         
            +
                      ].min
         
     | 
| 
      
 88 
     | 
    
         
            +
             
     | 
| 
      
 89 
     | 
    
         
            +
                      @last_timestamp = timestamp
         
     | 
| 
      
 90 
     | 
    
         
            +
                    end
         
     | 
| 
      
 91 
     | 
    
         
            +
             
     | 
| 
      
 92 
     | 
    
         
            +
                    def token_bucket_update_rate(new_rps)
         
     | 
| 
      
 93 
     | 
    
         
            +
                      # Refill based on our current rate before we update to the
         
     | 
| 
      
 94 
     | 
    
         
            +
                      # new fill rate
         
     | 
| 
      
 95 
     | 
    
         
            +
                      token_bucket_refill
         
     | 
| 
      
 96 
     | 
    
         
            +
                      @fill_rate = [new_rps, MIN_FILL_RATE].max
         
     | 
| 
      
 97 
     | 
    
         
            +
                      @max_capacity = [new_rps, MIN_CAPACITY].max
         
     | 
| 
      
 98 
     | 
    
         
            +
                      # When we scale down we can't have a current capacity that exceeds our
         
     | 
| 
      
 99 
     | 
    
         
            +
                      # max_capacity.
         
     | 
| 
      
 100 
     | 
    
         
            +
                      @current_capacity = [@current_capacity, @max_capacity].min
         
     | 
| 
      
 101 
     | 
    
         
            +
                    end
         
     | 
| 
      
 102 
     | 
    
         
            +
             
     | 
| 
      
 103 
     | 
    
         
            +
                    def enable_token_bucket
         
     | 
| 
      
 104 
     | 
    
         
            +
                      @enabled = true
         
     | 
| 
      
 105 
     | 
    
         
            +
                    end
         
     | 
| 
      
 106 
     | 
    
         
            +
             
     | 
| 
      
 107 
     | 
    
         
            +
                    def update_measured_rate
         
     | 
| 
      
 108 
     | 
    
         
            +
                      t = Aws::Util.monotonic_seconds
         
     | 
| 
      
 109 
     | 
    
         
            +
                      time_bucket = (t * 2).floor / 2.0
         
     | 
| 
      
 110 
     | 
    
         
            +
                      @request_count += 1
         
     | 
| 
      
 111 
     | 
    
         
            +
                      if time_bucket > @last_tx_rate_bucket
         
     | 
| 
      
 112 
     | 
    
         
            +
                        current_rate = @request_count / (time_bucket - @last_tx_rate_bucket)
         
     | 
| 
      
 113 
     | 
    
         
            +
                        @measured_tx_rate = (current_rate * SMOOTH) +
         
     | 
| 
      
 114 
     | 
    
         
            +
                          (@measured_tx_rate * (1 - SMOOTH))
         
     | 
| 
      
 115 
     | 
    
         
            +
                        @request_count = 0
         
     | 
| 
      
 116 
     | 
    
         
            +
                        @last_tx_rate_bucket = time_bucket
         
     | 
| 
      
 117 
     | 
    
         
            +
                      end
         
     | 
| 
      
 118 
     | 
    
         
            +
                    end
         
     | 
| 
      
 119 
     | 
    
         
            +
             
     | 
| 
      
 120 
     | 
    
         
            +
                    def calculate_time_window
         
     | 
| 
      
 121 
     | 
    
         
            +
                      # This is broken out into a separate calculation because it only
         
     | 
| 
      
 122 
     | 
    
         
            +
                      # gets updated when @last_max_rate changes so it can be cached.
         
     | 
| 
      
 123 
     | 
    
         
            +
                      @time_window = ((@last_max_rate * (1 - BETA)) / SCALE_CONSTANT)**(1.0 / 3)
         
     | 
| 
      
 124 
     | 
    
         
            +
                    end
         
     | 
| 
      
 125 
     | 
    
         
            +
             
     | 
| 
      
 126 
     | 
    
         
            +
                    def cubic_success(timestamp)
         
     | 
| 
      
 127 
     | 
    
         
            +
                      dt = timestamp - @last_throttle_time
         
     | 
| 
      
 128 
     | 
    
         
            +
                      (SCALE_CONSTANT * ((dt - @time_window)**3)) + @last_max_rate
         
     | 
| 
      
 129 
     | 
    
         
            +
                    end
         
     | 
| 
      
 130 
     | 
    
         
            +
             
     | 
| 
      
 131 
     | 
    
         
            +
                    def cubic_throttle(rate_to_use)
         
     | 
| 
      
 132 
     | 
    
         
            +
                      rate_to_use * BETA
         
     | 
| 
      
 133 
     | 
    
         
            +
                    end
         
     | 
| 
      
 134 
     | 
    
         
            +
                  end
         
     | 
| 
      
 135 
     | 
    
         
            +
                end
         
     | 
| 
      
 136 
     | 
    
         
            +
              end
         
     | 
| 
      
 137 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,63 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Aws
         
     | 
| 
      
 2 
     | 
    
         
            +
              module Plugins
         
     | 
| 
      
 3 
     | 
    
         
            +
                module Retries
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
                  # @api private
         
     | 
| 
      
 6 
     | 
    
         
            +
                  class ClockSkew
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
                    CLOCK_SKEW_THRESHOLD = 5 * 60 # five minutes
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
                    def initialize
         
     | 
| 
      
 11 
     | 
    
         
            +
                      @mutex = Mutex.new
         
     | 
| 
      
 12 
     | 
    
         
            +
                      @endpoint_clock_corrections = Hash.new(0)
         
     | 
| 
      
 13 
     | 
    
         
            +
                    end
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                    # Gets the clock_correction in seconds to apply to a given endpoint
         
     | 
| 
      
 16 
     | 
    
         
            +
                    # @param endpoint [URI / String]
         
     | 
| 
      
 17 
     | 
    
         
            +
                    def clock_correction(endpoint)
         
     | 
| 
      
 18 
     | 
    
         
            +
                      @mutex.synchronize { @endpoint_clock_corrections[endpoint.to_s] }
         
     | 
| 
      
 19 
     | 
    
         
            +
                    end
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
                    # Sets the clock correction for an endpoint
         
     | 
| 
      
 22 
     | 
    
         
            +
                    # @param endpoint [URI / String]
         
     | 
| 
      
 23 
     | 
    
         
            +
                    # @param correction [Number]
         
     | 
| 
      
 24 
     | 
    
         
            +
                    def set_clock_correction(endpoint, correction)
         
     | 
| 
      
 25 
     | 
    
         
            +
                      @mutex.synchronize { @endpoint_clock_corrections[endpoint.to_s] = correction }
         
     | 
| 
      
 26 
     | 
    
         
            +
                    end
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
                    # Determines whether a request has clock skew by comparing
         
     | 
| 
      
 29 
     | 
    
         
            +
                    # the current time against the server's time in the response
         
     | 
| 
      
 30 
     | 
    
         
            +
                    # @param context [Seahorse::Client::RequestContext]
         
     | 
| 
      
 31 
     | 
    
         
            +
                    def clock_skewed?(context)
         
     | 
| 
      
 32 
     | 
    
         
            +
                      server_time = server_time(context.http_response)
         
     | 
| 
      
 33 
     | 
    
         
            +
                      !!server_time && (Time.now.utc - server_time).abs > CLOCK_SKEW_THRESHOLD
         
     | 
| 
      
 34 
     | 
    
         
            +
                    end
         
     | 
| 
      
 35 
     | 
    
         
            +
             
     | 
| 
      
 36 
     | 
    
         
            +
                    # Update the stored clock skew value for an endpoint
         
     | 
| 
      
 37 
     | 
    
         
            +
                    # from the server's time in the response
         
     | 
| 
      
 38 
     | 
    
         
            +
                    # @param context [Seahorse::Client::RequestContext]
         
     | 
| 
      
 39 
     | 
    
         
            +
                    def update_clock_skew(context)
         
     | 
| 
      
 40 
     | 
    
         
            +
                      endpoint = context.http_request.endpoint
         
     | 
| 
      
 41 
     | 
    
         
            +
                      now_utc = Time.now.utc
         
     | 
| 
      
 42 
     | 
    
         
            +
                      server_time = server_time(context.http_response)
         
     | 
| 
      
 43 
     | 
    
         
            +
                      if server_time && (now_utc - server_time).abs > CLOCK_SKEW_THRESHOLD
         
     | 
| 
      
 44 
     | 
    
         
            +
                        set_clock_correction(endpoint, server_time - now_utc)
         
     | 
| 
      
 45 
     | 
    
         
            +
                      end
         
     | 
| 
      
 46 
     | 
    
         
            +
                    end
         
     | 
| 
      
 47 
     | 
    
         
            +
             
     | 
| 
      
 48 
     | 
    
         
            +
                    private
         
     | 
| 
      
 49 
     | 
    
         
            +
             
     | 
| 
      
 50 
     | 
    
         
            +
                    # @param response [Seahorse::Client::Http::Response:]
         
     | 
| 
      
 51 
     | 
    
         
            +
                    def server_time(response)
         
     | 
| 
      
 52 
     | 
    
         
            +
                      begin
         
     | 
| 
      
 53 
     | 
    
         
            +
                        Time.parse(response.headers['date']).utc
         
     | 
| 
      
 54 
     | 
    
         
            +
                      rescue
         
     | 
| 
      
 55 
     | 
    
         
            +
                        nil
         
     | 
| 
      
 56 
     | 
    
         
            +
                      end
         
     | 
| 
      
 57 
     | 
    
         
            +
                    end
         
     | 
| 
      
 58 
     | 
    
         
            +
             
     | 
| 
      
 59 
     | 
    
         
            +
                  end
         
     | 
| 
      
 60 
     | 
    
         
            +
                end
         
     | 
| 
      
 61 
     | 
    
         
            +
              end
         
     | 
| 
      
 62 
     | 
    
         
            +
            end
         
     | 
| 
      
 63 
     | 
    
         
            +
             
     | 
| 
         @@ -0,0 +1,142 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Aws
         
     | 
| 
      
 2 
     | 
    
         
            +
              module Plugins
         
     | 
| 
      
 3 
     | 
    
         
            +
                module Retries
         
     | 
| 
      
 4 
     | 
    
         
            +
                  # @api private
         
     | 
| 
      
 5 
     | 
    
         
            +
                  # This class will be obsolete when APIs contain modeled exceptions
         
     | 
| 
      
 6 
     | 
    
         
            +
                  class ErrorInspector
         
     | 
| 
      
 7 
     | 
    
         
            +
                    EXPIRED_CREDS = Set.new(
         
     | 
| 
      
 8 
     | 
    
         
            +
                      [
         
     | 
| 
      
 9 
     | 
    
         
            +
                        'InvalidClientTokenId',        # query services
         
     | 
| 
      
 10 
     | 
    
         
            +
                        'UnrecognizedClientException', # json services
         
     | 
| 
      
 11 
     | 
    
         
            +
                        'InvalidAccessKeyId',          # s3
         
     | 
| 
      
 12 
     | 
    
         
            +
                        'AuthFailure',                 # ec2
         
     | 
| 
      
 13 
     | 
    
         
            +
                        'InvalidIdentityToken',        # sts
         
     | 
| 
      
 14 
     | 
    
         
            +
                        'ExpiredToken'                 # route53
         
     | 
| 
      
 15 
     | 
    
         
            +
                      ]
         
     | 
| 
      
 16 
     | 
    
         
            +
                    )
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
                    THROTTLING_ERRORS = Set.new(
         
     | 
| 
      
 19 
     | 
    
         
            +
                      [
         
     | 
| 
      
 20 
     | 
    
         
            +
                        'Throttling',                             # query services
         
     | 
| 
      
 21 
     | 
    
         
            +
                        'ThrottlingException',                    # json services
         
     | 
| 
      
 22 
     | 
    
         
            +
                        'ThrottledException',                     # sns
         
     | 
| 
      
 23 
     | 
    
         
            +
                        'RequestThrottled',                       # sqs
         
     | 
| 
      
 24 
     | 
    
         
            +
                        'RequestThrottledException',              # generic service
         
     | 
| 
      
 25 
     | 
    
         
            +
                        'ProvisionedThroughputExceededException', # dynamodb
         
     | 
| 
      
 26 
     | 
    
         
            +
                        'TransactionInProgressException',         # dynamodb
         
     | 
| 
      
 27 
     | 
    
         
            +
                        'RequestLimitExceeded',                   # ec2
         
     | 
| 
      
 28 
     | 
    
         
            +
                        'BandwidthLimitExceeded',                 # cloud search
         
     | 
| 
      
 29 
     | 
    
         
            +
                        'LimitExceededException',                 # kinesis
         
     | 
| 
      
 30 
     | 
    
         
            +
                        'TooManyRequestsException',               # batch
         
     | 
| 
      
 31 
     | 
    
         
            +
                        'PriorRequestNotComplete',                # route53
         
     | 
| 
      
 32 
     | 
    
         
            +
                        'SlowDown',                               # s3
         
     | 
| 
      
 33 
     | 
    
         
            +
                        'EC2ThrottledException'                   # ec2
         
     | 
| 
      
 34 
     | 
    
         
            +
                      ]
         
     | 
| 
      
 35 
     | 
    
         
            +
                    )
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
      
 37 
     | 
    
         
            +
                    CHECKSUM_ERRORS = Set.new(
         
     | 
| 
      
 38 
     | 
    
         
            +
                      [
         
     | 
| 
      
 39 
     | 
    
         
            +
                        'CRC32CheckFailed' # dynamodb
         
     | 
| 
      
 40 
     | 
    
         
            +
                      ]
         
     | 
| 
      
 41 
     | 
    
         
            +
                    )
         
     | 
| 
      
 42 
     | 
    
         
            +
             
     | 
| 
      
 43 
     | 
    
         
            +
                    NETWORKING_ERRORS = Set.new(
         
     | 
| 
      
 44 
     | 
    
         
            +
                      [
         
     | 
| 
      
 45 
     | 
    
         
            +
                        'RequestTimeout',          # s3
         
     | 
| 
      
 46 
     | 
    
         
            +
                        'RequestTimeoutException', # glacier
         
     | 
| 
      
 47 
     | 
    
         
            +
                        'IDPCommunicationError'    # sts
         
     | 
| 
      
 48 
     | 
    
         
            +
                      ]
         
     | 
| 
      
 49 
     | 
    
         
            +
                    )
         
     | 
| 
      
 50 
     | 
    
         
            +
             
     | 
| 
      
 51 
     | 
    
         
            +
                    # See: https://github.com/aws/aws-sdk-net/blob/5810dfe401e0eac2e59d02276d4b479224b4538e/sdk/src/Core/Amazon.Runtime/Pipeline/RetryHandler/RetryPolicy.cs#L78
         
     | 
| 
      
 52 
     | 
    
         
            +
                    CLOCK_SKEW_ERRORS = Set.new(
         
     | 
| 
      
 53 
     | 
    
         
            +
                      [
         
     | 
| 
      
 54 
     | 
    
         
            +
                        'RequestTimeTooSkewed',
         
     | 
| 
      
 55 
     | 
    
         
            +
                        'RequestExpired',
         
     | 
| 
      
 56 
     | 
    
         
            +
                        'InvalidSignatureException',
         
     | 
| 
      
 57 
     | 
    
         
            +
                        'SignatureDoesNotMatch',
         
     | 
| 
      
 58 
     | 
    
         
            +
                        'AuthFailure',
         
     | 
| 
      
 59 
     | 
    
         
            +
                        'RequestInTheFuture'
         
     | 
| 
      
 60 
     | 
    
         
            +
                      ]
         
     | 
| 
      
 61 
     | 
    
         
            +
                    )
         
     | 
| 
      
 62 
     | 
    
         
            +
             
     | 
| 
      
 63 
     | 
    
         
            +
                    def initialize(error, http_status_code)
         
     | 
| 
      
 64 
     | 
    
         
            +
                      @error = error
         
     | 
| 
      
 65 
     | 
    
         
            +
                      @name = extract_name(@error)
         
     | 
| 
      
 66 
     | 
    
         
            +
                      @http_status_code = http_status_code
         
     | 
| 
      
 67 
     | 
    
         
            +
                    end
         
     | 
| 
      
 68 
     | 
    
         
            +
             
     | 
| 
      
 69 
     | 
    
         
            +
                    def expired_credentials?
         
     | 
| 
      
 70 
     | 
    
         
            +
                      !!(EXPIRED_CREDS.include?(@name) || @name.match(/expired/i))
         
     | 
| 
      
 71 
     | 
    
         
            +
                    end
         
     | 
| 
      
 72 
     | 
    
         
            +
             
     | 
| 
      
 73 
     | 
    
         
            +
                    def throttling_error?
         
     | 
| 
      
 74 
     | 
    
         
            +
                      !!(THROTTLING_ERRORS.include?(@name) ||
         
     | 
| 
      
 75 
     | 
    
         
            +
                        @name.match(/throttl/i) ||
         
     | 
| 
      
 76 
     | 
    
         
            +
                        @http_status_code == 429) ||
         
     | 
| 
      
 77 
     | 
    
         
            +
                        modeled_throttling?
         
     | 
| 
      
 78 
     | 
    
         
            +
                    end
         
     | 
| 
      
 79 
     | 
    
         
            +
             
     | 
| 
      
 80 
     | 
    
         
            +
                    def checksum?
         
     | 
| 
      
 81 
     | 
    
         
            +
                      CHECKSUM_ERRORS.include?(@name) || @error.is_a?(Errors::ChecksumError)
         
     | 
| 
      
 82 
     | 
    
         
            +
                    end
         
     | 
| 
      
 83 
     | 
    
         
            +
             
     | 
| 
      
 84 
     | 
    
         
            +
                    def networking?
         
     | 
| 
      
 85 
     | 
    
         
            +
                      @error.is_a?(Seahorse::Client::NetworkingError) ||
         
     | 
| 
      
 86 
     | 
    
         
            +
                        @error.is_a?(Errors::NoSuchEndpointError) ||
         
     | 
| 
      
 87 
     | 
    
         
            +
                        NETWORKING_ERRORS.include?(@name)
         
     | 
| 
      
 88 
     | 
    
         
            +
                    end
         
     | 
| 
      
 89 
     | 
    
         
            +
             
     | 
| 
      
 90 
     | 
    
         
            +
                    def server?
         
     | 
| 
      
 91 
     | 
    
         
            +
                      (500..599).cover?(@http_status_code)
         
     | 
| 
      
 92 
     | 
    
         
            +
                    end
         
     | 
| 
      
 93 
     | 
    
         
            +
             
     | 
| 
      
 94 
     | 
    
         
            +
                    def endpoint_discovery?(context)
         
     | 
| 
      
 95 
     | 
    
         
            +
                      return false unless context.operation.endpoint_discovery
         
     | 
| 
      
 96 
     | 
    
         
            +
             
     | 
| 
      
 97 
     | 
    
         
            +
                      @http_status_code == 421 ||
         
     | 
| 
      
 98 
     | 
    
         
            +
                        @name == 'InvalidEndpointException' ||
         
     | 
| 
      
 99 
     | 
    
         
            +
                        @error.is_a?(Errors::EndpointDiscoveryError)
         
     | 
| 
      
 100 
     | 
    
         
            +
                    end
         
     | 
| 
      
 101 
     | 
    
         
            +
             
     | 
| 
      
 102 
     | 
    
         
            +
                    def modeled_retryable?
         
     | 
| 
      
 103 
     | 
    
         
            +
                      @error.is_a?(Errors::ServiceError) && @error.retryable?
         
     | 
| 
      
 104 
     | 
    
         
            +
                    end
         
     | 
| 
      
 105 
     | 
    
         
            +
             
     | 
| 
      
 106 
     | 
    
         
            +
                    def modeled_throttling?
         
     | 
| 
      
 107 
     | 
    
         
            +
                      @error.is_a?(Errors::ServiceError) && @error.throttling?
         
     | 
| 
      
 108 
     | 
    
         
            +
                    end
         
     | 
| 
      
 109 
     | 
    
         
            +
             
     | 
| 
      
 110 
     | 
    
         
            +
                    def clock_skew?(context)
         
     | 
| 
      
 111 
     | 
    
         
            +
                      CLOCK_SKEW_ERRORS.include?(@name) &&
         
     | 
| 
      
 112 
     | 
    
         
            +
                        context.config.clock_skew.clock_skewed?(context)
         
     | 
| 
      
 113 
     | 
    
         
            +
                    end
         
     | 
| 
      
 114 
     | 
    
         
            +
             
     | 
| 
      
 115 
     | 
    
         
            +
                    def retryable?(context)
         
     | 
| 
      
 116 
     | 
    
         
            +
                      server? ||
         
     | 
| 
      
 117 
     | 
    
         
            +
                        modeled_retryable? ||
         
     | 
| 
      
 118 
     | 
    
         
            +
                        throttling_error? ||
         
     | 
| 
      
 119 
     | 
    
         
            +
                        networking? ||
         
     | 
| 
      
 120 
     | 
    
         
            +
                        checksum? ||
         
     | 
| 
      
 121 
     | 
    
         
            +
                        endpoint_discovery?(context) ||
         
     | 
| 
      
 122 
     | 
    
         
            +
                        (expired_credentials? && refreshable_credentials?(context)) ||
         
     | 
| 
      
 123 
     | 
    
         
            +
                        clock_skew?(context)
         
     | 
| 
      
 124 
     | 
    
         
            +
                    end
         
     | 
| 
      
 125 
     | 
    
         
            +
             
     | 
| 
      
 126 
     | 
    
         
            +
                    private
         
     | 
| 
      
 127 
     | 
    
         
            +
             
     | 
| 
      
 128 
     | 
    
         
            +
                    def refreshable_credentials?(context)
         
     | 
| 
      
 129 
     | 
    
         
            +
                      context.config.credentials.respond_to?(:refresh!)
         
     | 
| 
      
 130 
     | 
    
         
            +
                    end
         
     | 
| 
      
 131 
     | 
    
         
            +
             
     | 
| 
      
 132 
     | 
    
         
            +
                    def extract_name(error)
         
     | 
| 
      
 133 
     | 
    
         
            +
                      if error.is_a?(Errors::ServiceError)
         
     | 
| 
      
 134 
     | 
    
         
            +
                        error.class.code || error.class.name.to_s
         
     | 
| 
      
 135 
     | 
    
         
            +
                      else
         
     | 
| 
      
 136 
     | 
    
         
            +
                        error.class.name.to_s
         
     | 
| 
      
 137 
     | 
    
         
            +
                      end
         
     | 
| 
      
 138 
     | 
    
         
            +
                    end
         
     | 
| 
      
 139 
     | 
    
         
            +
                  end
         
     | 
| 
      
 140 
     | 
    
         
            +
                end
         
     | 
| 
      
 141 
     | 
    
         
            +
              end
         
     | 
| 
      
 142 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,57 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Aws
         
     | 
| 
      
 2 
     | 
    
         
            +
              module Plugins
         
     | 
| 
      
 3 
     | 
    
         
            +
                module Retries
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
                  # @api private
         
     | 
| 
      
 6 
     | 
    
         
            +
                  # Used in 'standard' and 'adaptive' retry modes.
         
     | 
| 
      
 7 
     | 
    
         
            +
                  class RetryQuota
         
     | 
| 
      
 8 
     | 
    
         
            +
                    INITIAL_RETRY_TOKENS = 500
         
     | 
| 
      
 9 
     | 
    
         
            +
                    RETRY_COST = 5
         
     | 
| 
      
 10 
     | 
    
         
            +
                    NO_RETRY_INCREMENT = 1
         
     | 
| 
      
 11 
     | 
    
         
            +
                    TIMEOUT_RETRY_COST = 10
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
                    def initialize(opts = {})
         
     | 
| 
      
 14 
     | 
    
         
            +
                      @mutex              = Mutex.new
         
     | 
| 
      
 15 
     | 
    
         
            +
                      @max_capacity       = opts.fetch(:max_capacity, INITIAL_RETRY_TOKENS)
         
     | 
| 
      
 16 
     | 
    
         
            +
                      @available_capacity = @max_capacity
         
     | 
| 
      
 17 
     | 
    
         
            +
                    end
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
                    # check if there is sufficient capacity to retry
         
     | 
| 
      
 20 
     | 
    
         
            +
                    # and return it.  If there is insufficient capacity
         
     | 
| 
      
 21 
     | 
    
         
            +
                    # return 0
         
     | 
| 
      
 22 
     | 
    
         
            +
                    # @return [Integer] The amount of capacity checked out
         
     | 
| 
      
 23 
     | 
    
         
            +
                    def checkout_capacity(error_inspector)
         
     | 
| 
      
 24 
     | 
    
         
            +
                      @mutex.synchronize do
         
     | 
| 
      
 25 
     | 
    
         
            +
                        capacity_amount = if error_inspector.networking?
         
     | 
| 
      
 26 
     | 
    
         
            +
                                            TIMEOUT_RETRY_COST
         
     | 
| 
      
 27 
     | 
    
         
            +
                                          else
         
     | 
| 
      
 28 
     | 
    
         
            +
                                            RETRY_COST
         
     | 
| 
      
 29 
     | 
    
         
            +
                                          end
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
                        # unable to acquire capacity
         
     | 
| 
      
 32 
     | 
    
         
            +
                        return 0 if capacity_amount > @available_capacity
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
                        @available_capacity -= capacity_amount
         
     | 
| 
      
 35 
     | 
    
         
            +
                        capacity_amount
         
     | 
| 
      
 36 
     | 
    
         
            +
                      end
         
     | 
| 
      
 37 
     | 
    
         
            +
                    end
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
                    # capacity_amount refers to the amount of capacity requested from
         
     | 
| 
      
 40 
     | 
    
         
            +
                    # the last retry.  It can either be RETRY_COST, TIMEOUT_RETRY_COST,
         
     | 
| 
      
 41 
     | 
    
         
            +
                    # or unset.
         
     | 
| 
      
 42 
     | 
    
         
            +
                    def release(capacity_amount)
         
     | 
| 
      
 43 
     | 
    
         
            +
                      # Implementation note:  The release() method is called for
         
     | 
| 
      
 44 
     | 
    
         
            +
                      # every API call.  In the common case where the request is
         
     | 
| 
      
 45 
     | 
    
         
            +
                      # successful and we're at full capacity, we can avoid locking.
         
     | 
| 
      
 46 
     | 
    
         
            +
                      # We can't exceed max capacity so there's no work we have to do.
         
     | 
| 
      
 47 
     | 
    
         
            +
                      return if @available_capacity == @max_capacity
         
     | 
| 
      
 48 
     | 
    
         
            +
             
     | 
| 
      
 49 
     | 
    
         
            +
                      @mutex.synchronize do
         
     | 
| 
      
 50 
     | 
    
         
            +
                        @available_capacity += capacity_amount || NO_RETRY_INCREMENT
         
     | 
| 
      
 51 
     | 
    
         
            +
                        @available_capacity = [@available_capacity, @max_capacity].min
         
     | 
| 
      
 52 
     | 
    
         
            +
                      end
         
     | 
| 
      
 53 
     | 
    
         
            +
                    end
         
     | 
| 
      
 54 
     | 
    
         
            +
                  end
         
     | 
| 
      
 55 
     | 
    
         
            +
                end
         
     | 
| 
      
 56 
     | 
    
         
            +
              end
         
     | 
| 
      
 57 
     | 
    
         
            +
            end
         
     |