Class: Azure::Storage::Common::Core::Filter::RetryPolicyFilter
- Inherits:
-
Core::Http::RetryPolicy
- Object
- Core::Http::RetryPolicy
- Azure::Storage::Common::Core::Filter::RetryPolicyFilter
- Defined in:
- lib/azure/storage/common/core/filter/retry_filter.rb
Direct Known Subclasses
Instance Attribute Summary collapse
-
#retry_count ⇒ Object
readonly
Returns the value of attribute retry_count.
-
#retry_interval ⇒ Object
readonly
Returns the value of attribute retry_interval.
Instance Method Summary collapse
-
#adjust_retry_request(retry_data) ⇒ Object
Adjust the retry request.
-
#apply_retry_policy(retry_data) ⇒ Object
Apply the retry policy to determine how the HTTP request should continue retrying.
-
#check_location(response, retry_data) ⇒ Object
Check the location.
-
#check_status_code(retry_data) ⇒ Object
Check the status code.
-
#get_next_location(retry_data) ⇒ Object
Get retry request destination.
-
#init_retry_data(retry_data) ⇒ Object
Initialize the retry data.
-
#initialize(retry_count = nil, retry_interval = nil) ⇒ RetryPolicyFilter
constructor
A new instance of RetryPolicyFilter.
-
#should_retry?(response, retry_data) ⇒ Boolean
Overrides the base class implementation of call to determine whether to retry the operation.
-
#should_retry_on_error?(response, retry_data) ⇒ Boolean
Determines if the HTTP request should continue retrying.
-
#should_retry_on_local_error?(retry_data) ⇒ Boolean
Determines if the HTTP request should continue retrying.
-
#wait_for_retry ⇒ Object
Adjust the retry parameter and wait for retry.
Constructor Details
#initialize(retry_count = nil, retry_interval = nil) ⇒ RetryPolicyFilter
Returns a new instance of RetryPolicyFilter.
31 32 33 34 35 36 37 |
# File 'lib/azure/storage/common/core/filter/retry_filter.rb', line 31 def initialize(retry_count = nil, retry_interval = nil) @retry_count = retry_count @retry_interval = retry_interval @request_options = {} super &:should_retry? end |
Instance Attribute Details
#retry_count ⇒ Object (readonly)
Returns the value of attribute retry_count.
39 40 41 |
# File 'lib/azure/storage/common/core/filter/retry_filter.rb', line 39 def retry_count @retry_count end |
#retry_interval ⇒ Object (readonly)
Returns the value of attribute retry_interval.
39 40 41 |
# File 'lib/azure/storage/common/core/filter/retry_filter.rb', line 39 def retry_interval @retry_interval end |
Instance Method Details
#adjust_retry_request(retry_data) ⇒ Object
Adjust the retry request
retry_data - Hash. Stores stateful retry data
158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 |
# File 'lib/azure/storage/common/core/filter/retry_filter.rb', line 158 def adjust_retry_request(retry_data) # Adjust the location first next_location = @request_options[:target_location].nil? ? get_next_location(retry_data) : @request_options[:target_location] retry_data[:current_location] = next_location retry_data[:uri] = if next_location == Azure::Storage::Common::StorageLocation::PRIMARY @request_options[:primary_uri] else @request_options[:secondary_uri] end # Now is the time to calculate the exact retry interval. ShouldRetry call above already # returned back how long two requests to the same location should be apart from each other. # However, for the reasons explained above, the time spent between the last attempt to # the target location and current time must be subtracted from the total retry interval # that ShouldRetry returned. lastAttemptTime = if retry_data[:current_location] == Azure::Storage::Common::StorageLocation::PRIMARY retry_data[:last_primary_attempt] else retry_data[:last_secondary_attempt] end @retry_interval = if lastAttemptTime.nil? 0 else since_last_attempt = Time.now - lastAttemptTime retry_data[:interval] - since_last_attempt end end |
#apply_retry_policy(retry_data) ⇒ Object
Apply the retry policy to determine how the HTTP request should continue retrying
retry_data - Hash. Stores stateful retry data
The retry_data is a Hash which can be used to store stateful data about the request execution context (such as an incrementing counter, timestamp, etc). The retry_data object will be the same instance throughout the lifetime of the request
Alternatively, a subclass could override this method.
85 86 |
# File 'lib/azure/storage/common/core/filter/retry_filter.rb', line 85 def apply_retry_policy(retry_data) end |
#check_location(response, retry_data) ⇒ Object
Check the location
retry_data - Hash. Stores stateful retry data
211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 |
# File 'lib/azure/storage/common/core/filter/retry_filter.rb', line 211 def check_location(response, retry_data) # If a request sent to the secondary location fails with 404 (Not Found), it is possible # that the resource replication is not finished yet. So, in case of 404 only in the secondary # location, the failure should still be retryable. retry_data[:secondary_not_found] = (retry_data[:current_location] === Azure::Storage::Common::StorageLocation::SECONDARY) && response.status_code === 404; if retry_data[:secondary_not_found] retry_data[:status_code] = 500 else if (response.status_code) retry_data[:status_code] = response.status_code else retry_data[:status_code] = nil end end end |
#check_status_code(retry_data) ⇒ Object
Check the status code
retry_data - Hash. Stores stateful retry data
231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 |
# File 'lib/azure/storage/common/core/filter/retry_filter.rb', line 231 def check_status_code(retry_data) if (retry_data[:status_code] < 400) retry_data[:retryable] = false; # Non-timeout Cases elsif (retry_data[:status_code] != 408) # Always no retry on "not implemented" and "version not supported" if (retry_data[:status_code] == 501 || retry_data[:status_code] == 505) retry_data[:retryable] = false; end if (retry_data[:status_code] == 404) retry_data[:retryable] = true; return true; end # When absorb_conditional_errors_on_retry is set (for append blob) if (@request_options[:absorb_conditional_errors_on_retry]) if (retry_data[:status_code] == 412) # When appending block with precondition failure and their was a server error before, we ignore the error. if (retry_data[:last_server_error]) retry_data[:error] = nil; retry_data[:retryable] = true; else retry_data[:retryable] = false; end elsif (retry_data[:retryable] && retry_data[:status_code] >= 500 && retry_data[:status_code] < 600) # Retry on the server error retry_data[:retryable] = true; retry_data[:last_server_error] = true; end elsif (retry_data[:status_code] < 500) # No retry on the client error retry_data[:retryable] = false; end end end |
#get_next_location(retry_data) ⇒ Object
Get retry request destination
retry_data - Hash. Stores stateful retry data
271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 |
# File 'lib/azure/storage/common/core/filter/retry_filter.rb', line 271 def get_next_location(retry_data) # In case of 404 when trying the secondary location, instead of retrying on the # secondary, further requests should be sent only to the primary location, as it most # probably has a higher chance of succeeding there. if retry_data[:secondary_not_found] && @request_options[:location_mode] != Azure::Storage::Common::LocationMode::SECONDARY_ONLY @request_options[:location_mode] = Azure::Storage::Common::LocationMode::PRIMARY_ONLY; return Azure::Storage::Common::StorageLocation::PRIMARY end case @request_options[:location_mode] when Azure::Storage::Common::LocationMode::PRIMARY_ONLY Azure::Storage::Common::StorageLocation::PRIMARY when Azure::Storage::Common::LocationMode::SECONDARY_ONLY Azure::Storage::Common::StorageLocation::SECONDARY else # request_location_mode cannot be SECONDARY_ONLY because it will be blocked at the first time if @request_options[:request_location_mode] == Azure::Storage::Common::RequestLocationMode::PRIMARY_ONLY Azure::Storage::Common::StorageLocation::PRIMARY elsif @request_options[:request_location_mode] == Azure::Storage::Common::RequestLocationMode::SECONDARY_ONLY Azure::Storage::Common::StorageLocation::SECONDARY else if retry_data[:current_location] === Azure::Storage::Common::StorageLocation::PRIMARY Azure::Storage::Common::StorageLocation::SECONDARY else Azure::Storage::Common::StorageLocation::PRIMARY end end end end |
#init_retry_data(retry_data) ⇒ Object
Initialize the retry data
retry_data - Hash. Stores stateful retry data
194 195 196 197 198 199 200 201 202 203 204 205 206 |
# File 'lib/azure/storage/common/core/filter/retry_filter.rb', line 194 def init_retry_data(retry_data) @request_options = retry_data[:request_options] unless retry_data[:request_options].nil? if retry_data[:current_location].nil? retry_data[:current_location] = Azure::Storage::Common::Service::StorageService.get_location(@request_options[:location_mode], @request_options[:request_location_mode]) end if retry_data[:current_location] == Azure::Storage::Common::StorageLocation::PRIMARY retry_data[:last_primary_attempt] = Time.now else retry_data[:last_secondary_attempt] = Time.now end end |
#should_retry?(response, retry_data) ⇒ Boolean
Overrides the base class implementation of call to determine whether to retry the operation
response - HttpResponse. The response from the active request retry_data - Hash. Stores stateful retry data
47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 |
# File 'lib/azure/storage/common/core/filter/retry_filter.rb', line 47 def should_retry?(response, retry_data) # Fill necessary information init_retry_data retry_data # Applies the logic when there is subclass overrides it apply_retry_policy retry_data # Checks the result and count limit if retry_data[:retryable].nil? retry_data[:retryable] = true else retry_data[:retryable] &&= retry_data[:count] <= @retry_count end return false unless retry_data[:retryable] # Checks whether there is a local error # Cannot retry immediately when it returns true, as it need check other errors should_retry_on_local_error? retry_data return false unless should_retry_on_error? response, retry_data # Determined that it needs to retry. adjust_retry_request retry_data wait_for_retry retry_data[:retryable] end |
#should_retry_on_error?(response, retry_data) ⇒ Boolean
Determines if the HTTP request should continue retrying
response - Azure::Core::Http::HttpResponse. The response from the active request retry_data - Hash. Stores stateful retry data
The retry_data is a Hash which can be used to store stateful data about the request execution context (such as an incrementing counter, timestamp, etc). The retry_data object will be the same instance throughout the lifetime of the request.
136 137 138 139 140 141 142 143 144 145 146 147 148 |
# File 'lib/azure/storage/common/core/filter/retry_filter.rb', line 136 def should_retry_on_error?(response, retry_data) response = response || retry_data[:error].http_response if retry_data[:error] && retry_data[:error].respond_to?("http_response") unless response retry_data[:retryable] = false unless retry_data[:error] return retry_data[:retryable] end check_location(response, retry_data) check_status_code(retry_data) retry_data[:retryable] end |
#should_retry_on_local_error?(retry_data) ⇒ Boolean
Determines if the HTTP request should continue retrying
retry_data - Hash. Stores stateful retry data
The retry_data is a Hash which can be used to store stateful data about the request execution context (such as an incrementing counter, timestamp, etc). The retry_data object will be the same instance throughout the lifetime of the request.
96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 |
# File 'lib/azure/storage/common/core/filter/retry_filter.rb', line 96 def should_retry_on_local_error?(retry_data) unless retry_data[:error] retry_data[:retryable] = true; return true end = retry_data[:error].inspect if .include?("SocketError: Hostname not known") # Retry on local DNS resolving # When uses resolv-replace.rb to replace the libc resolver # Reference: # https://makandracards.com/ninjaconcept/30815-fixing-socketerror-getaddrinfo-name-or-service-not-known-with-ruby-s-resolv-replace-rb # http://www.subelsky.com/2014/05/fixing-socketerror-getaddrinfo-name-or.html retry_data[:retryable] = true; elsif .include?("getaddrinfo: Name or service not known") # When uses the default resolver retry_data[:retryable] = true; elsif .downcase.include?("timeout") retry_data[:retryable] = true; elsif .include?("Errno::ECONNRESET") retry_data[:retryable] = true; elsif .include?("Errno::EACCES") retry_data[:retryable] = false; elsif .include?("NOSUPPORT") retry_data[:retryable] = false; end retry_data[:retryable] end |
#wait_for_retry ⇒ Object
Adjust the retry parameter and wait for retry
151 152 153 |
# File 'lib/azure/storage/common/core/filter/retry_filter.rb', line 151 def wait_for_retry sleep @retry_interval end |