neglectedvalue/yup

View on GitHub
lib/yup/request_forwarder.rb

Summary

Maintainability
A
3 hrs
Test Coverage
require 'em-http-request'

module Yup
  class RequestForwarder
    def initialize(http_method, request_url, headers, body, forward_to, timeout)
      @http_method = http_method
      @request_url = request_url
      @headers     = headers
      @body        = body
      @forward_to  = forward_to
      @timeout     = timeout
      @logger      = Yup.logger.clone

      @headers.merge!(
        'Host'       => @forward_to,
        'Connection' => 'Close')
    end

    def perform
      http_method = @http_method.to_sym
      http_url    = "http://#{@forward_to}#{@request_url}"
      http = EventMachine::HttpRequest.
        new(http_url,
            :inactivity_timeout => @timeout).
        send(http_method,
             :head => @headers,
             :body => @body)

      @logger.progname = "Yup::RequestForwarder (##{self.__id__.to_s(36)} received at #{Time.now.to_s})"

      http.callback do
        Yup.watermark += 1

        if http.response_header && http.response_header.status && http.response_header.status / 100 == 2
          log_response(http)
          @logger.info "Success"
        else
          log_response(http)
          if Yup.retry_unless_2xx
            @logger.info "Fail: got status code #{http.response_header.status}; will retry after #{Yup.resend_delay} seconds"
            EventMachine.add_timer(Yup.resend_delay, &self.method(:retry))
          else
            @logger.info "Fail; will not retry"
          end
        end
      end

      http.errback do
        log_response(http)
        @logger.info "Error: #{http.inspect}: #{http.error}; will retry after #{Yup.resend_delay} seconds"

        EventMachine.add_timer(Yup.resend_delay, &self.method(:retry))
      end
    end

    def retry
      self.perform
    end

  private
    def log_response(http)
      @logger.info { "HTTP request: #{@http_method.upcase} #{@request_url} HTTP/1.1" }
      if http.response_header.http_status
        @logger.info  { "HTTP response: HTTP/#{http.response_header.http_version} #{http.response_header.http_status} #{http.response_header.http_reason}" }
        @logger.debug { "HTTP response headers" + (http.response_header.empty? ? " is empty" : "\n" + http.response_header.inspect) }
        @logger.debug { "HTTP response body"    + (http.response.empty? ? " is empty" : "\n" + http.response.inspect) }
      end
    end
  end
end