def run
      cancel = Proc.new do
        msg = "Request #{@operation} timed out after #{@timeout} seconds"
        Log.info(msg)
        cancel(msg)
      end

      options = {}
      if @expires_at.nil? || (options[:time_to_live] = @expires_at - Time.now.to_i) > 0
        Sender.instance.send_request(@operation, @payload, retrieve_target(@targets), options) { |r| handle_response(r) }
        @cancel_timer = EM::Timer.new(@timeout) { cancel.call } if @cancel_timer.nil? && @timeout > 0
      else
        cancel.call
      end
      true
    end
def run
      cancel = Proc.new do
        msg = "Request #{@operation} timed out after #{@timeout} seconds"
        Log.info(msg)
        cancel(msg)
      end

      options = {}
      if @expires_at.nil? || (options[:time_to_live] = @expires_at - Time.now.to_i) > 0
        Sender.instance.send_request(@operation, @payload, retrieve_target(@targets), options) { |r| handle_response(r) }
        @cancel_timer = EM::Timer.new(@timeout) { cancel.call } if @cancel_timer.nil? && @timeout > 0
      else
        cancel.call
      end
      true
    end
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
 Send request and retry until timeout is reached or response is received
 Ignore duplicate responses

 === Return
 true:: Always return true