Class: RightScale::RetryableRequest
- Includes:
- EM::Deferrable, OperationResultHelper
- Defined in:
- lib/right_agent/retryable_request.rb
Overview
This is a retryable request for use when the execution of the request by the receiver is known to be idempotent and when there is a need to indefinitely pursue getting a usable response, e.g., when an instance is launching. It is implemented as an EM::Deferrable and as such invokes the Proc defined with its #callback method with the result content from a OperationResult::SUCCESS response, or it will invoke the Proc defined with its #errback method with error content if the response is an OperationResult::ERROR or CANCEL, or if the request has timed out. The request can be canceled with the #cancel method, or the receiver of the request may respond with a CANCEL result to cause the request to be canceled. This is useful in situations where the request is never expected to succeed regardless of the number of retries. By default if the response to the request is an OperationResult::RETRY or NON_DELIVERY indication, the request is automatically retried, as is also the case for an ERROR indication if the :retry_on_error option is specified. The retry algorithm is controlled by the :retry_delay, :retry_delay_count, and :max_retry_delay settings. The initial retry interval is the default or specified :retry_delay and this interval is used :retry_delay_count times, at which point the :retry_delay is doubled and the :retry_delay_count is halved. This backoff is again applied after the new :retry_delay_count is reached, and so on until :retry_delay reaches :max_retry_delay which then is used as the interval until the default or specified :timeout is reached. The default :timeout is 4 days.
Constant Summary collapse
- DEFAULT_RETRY_DELAY =
Default delay before initial retry in case of failure with -1 meaning no delay
5
- DEFAULT_RETRY_DELAY_COUNT =
Default minimum number of retries before beginning backoff
60
- DEFAULT_MAX_RETRY_DELAY =
Maximum default delay before retry when backing off
60
- RETRY_BACKOFF_FACTOR =
Factor used for exponential backoff of retry delay
2
- DEFAULT_TIMEOUT =
Default timeout with -1 meaning never timeout
4 * 24 * 60 * 60
Instance Attribute Summary collapse
-
#raw_response ⇒ Object
readonly
Returns the value of attribute raw_response.
Instance Method Summary collapse
-
#cancel(msg) ⇒ Object
Cancel request and call error callback.
-
#initialize(operation, payload, options = {}) ⇒ RetryableRequest
constructor
Send idempotent request Retry until timeout is reached (indefinitely if timeout <= 0) Calls deferrable callback on completion, error callback on timeout.
-
#run ⇒ Object
Send request and retry until timeout is reached or response is received Ignore duplicate responses.
Methods included from OperationResultHelper
#cancel_result, #continue_result, #error_result, #non_delivery_result, #result_from, #retry_result, #success_result
Constructor Details
#initialize(operation, payload, options = {}) ⇒ RetryableRequest
Send idempotent request Retry until timeout is reached (indefinitely if timeout <= 0) Calls deferrable callback on completion, error callback on timeout
Parameters
- operation(String)
-
Request operation (e.g., ‘/booter/get_boot_bundle’)
- payload(Hash)
-
Request payload
- options(Hash)
-
Request options
- :targets(Array)
-
Target agent identities from which to randomly choose one
- :retry_on_error(Boolean)
-
Whether request should be retried if recipient returned an error
- :retry_delay(Numeric)
-
Number of seconds delay before initial retry with -1 meaning no delay,
defaults to DEFAULT_RETRY_DELAY
:retry_delay_count(Numeric):: Minimum number of retries at initial :retry_delay value before
increasing delay exponentially and decreasing this count exponentially, defaults to
DEFAULT_RETRY_DELAY_COUNT
:max_retry_delay(Numeric):: Maximum number of seconds of retry delay, defaults to DEFAULT_MAX_RETRY_DELAY
:timeout(Numeric):: Number of seconds with no response before error callback gets called, with
-1 meaning never, defaults to DEFAULT_TIMEOUT
Raises
- ArgumentError
-
If operation or payload not specified
88 89 90 91 92 93 94 95 96 97 98 99 100 101 |
# File 'lib/right_agent/retryable_request.rb', line 88 def initialize(operation, payload, = {}) raise ArgumentError.new("operation is required") unless (@operation = operation) raise ArgumentError.new("payload is required") unless (@payload = payload) @retry_on_error = [:retry_on_error] @timeout = [:timeout] || DEFAULT_TIMEOUT @expires_at = Time.now.to_i + @timeout if @timeout > 0 @retry_delay = [:retry_delay] || DEFAULT_RETRY_DELAY @retry_delay_count = [:retry_delay_count] || DEFAULT_RETRY_DELAY_COUNT @max_retry_delay = [:max_retry_delay] || DEFAULT_MAX_RETRY_DELAY @retries = 0 @targets = [:targets] @raw_response = nil @done = false end |
Instance Attribute Details
#raw_response ⇒ Object (readonly)
Returns the value of attribute raw_response.
65 66 67 |
# File 'lib/right_agent/retryable_request.rb', line 65 def raw_response @raw_response end |
Instance Method Details
#cancel(msg) ⇒ Object
Cancel request and call error callback
Parameters
- msg(String)
-
Reason why request is cancelled, given to error callback
Return
- true
-
Always return true
132 133 134 135 136 137 138 139 140 |
# File 'lib/right_agent/retryable_request.rb', line 132 def cancel(msg) if @cancel_timer @cancel_timer.cancel @cancel_timer = nil end @done = true fail(msg) true end |
#run ⇒ Object
Send request and retry until timeout is reached or response is received Ignore duplicate responses
Return
- true
-
Always return true
108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 |
# File 'lib/right_agent/retryable_request.rb', line 108 def run cancel = Proc.new do msg = "Request #{@operation} timed out after #{@timeout} seconds" Log.info(msg) cancel(msg) end = {} if @expires_at.nil? || ([:time_to_live] = @expires_at - Time.now.to_i) > 0 Sender.instance.send_request(@operation, @payload, retrieve_target(@targets), ) { |r| handle_response(r) } @cancel_timer = EM::Timer.new(@timeout) { cancel.call } if @cancel_timer.nil? && @timeout > 0 else cancel.call end true end |