Module: LVS::JsonService::Request::ClassMethods

Defined in:
lib/lvs/json_service/request.rb

Instance Method Summary collapse

Instance Method Details

#http_standard_request_with_timeout(service, args, options) {|response| ... } ⇒ Object

Yields:

  • (response)


19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
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
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
# File 'lib/lvs/json_service/request.rb', line 19

def http_standard_request_with_timeout(service, args, options)
  uri = URI.parse(service)

  Rails.logger.debug("Options are #{options.inspect}")
  if options[:http_method] == :get
    path = uri.path
    path += "?#{uri.query}" unless uri.query.blank?
    req = Net::HTTP::Get.new(path)
    Rails.logger.debug("Getting '#{path}'")
  else
    req = Net::HTTP::Post.new(uri.path)
    req.form_data = { "object_request" => args.to_json }
    Rails.logger.debug("Posting to #{uri.path}")
  end
  req.basic_auth(uri.user, uri.password) unless uri.user.to_s == ""
  req.add_field("X-LVS-Request-ID", options[:request_id])
  
  options[:encrypted] ||= require_ssl?
  retries = options[:retries] || 0
  hard_retries = 1 # For persistent connection failures

  begin
    retries -= 1
            
    http = LVS::JsonService::ConnectionManager.get_connection(uri.host, uri.port, options)
    http.open_timeout = options[:timeout] || 1
    http.read_timeout = options[:timeout] || 1
    response = http.request(req)
    Rails.logger.debug("Request is #{req.inspect}")
    Rails.logger.debug("Response is #{response.body.inspect}")
  
  rescue Errno::EPIPE, EOFError, Errno::ECONNRESET, Errno::ECONNABORTED
    hard_retries -= 1
    if hard_retries >= 0
      sleep(1)
      LVS::JsonService::ConnectionManager.reset_connection(uri.host, uri.port, options)
      retry
    end
  
  rescue Timeout::Error => e
    LVS::JsonService::ConnectionManager.reset_connection(uri.host, uri.port, options)
    if retries >= 0
      LVS::JsonService::Logger.debug(
        "Retrying #{service} due to TimeoutError"
      )
      retry
    end
    raise LVS::JsonService::TimeoutError.new("Backend failed to respond in time (#{options[:timeout]}s)", 500, service, args)
            
  rescue Errno::ECONNREFUSED => e
    if retries >= 0
      LVS::JsonService::Logger.debug(
        "Retrying #{service} due to Errno::ECONNREFUSED"
      )
      sleep(1)  
      retry
    end
    raise LVS::JsonService::BackendUnavailableError.new("Backend unavailable", 500, service, args)
    
  rescue OpenSSL::SSL::SSLError => e
    raise LVS::JsonService::BackendUnavailableError.new("Backend unavailable #{e}", 500, service, args)
  end

  if response.is_a?(Net::HTTPNotFound)
    raise LVS::JsonService::NotFoundError.new("404 Found for the service #{service}", 404, service, args)
  end

  if response.is_a?(Net::HTTPNotModified)
    raise LVS::JsonService::NotModified.new("304 Data hasn't changed", 304, service, args)
  end

  yield(response)
end

#log_response(timing, body, options) ⇒ Object



135
136
137
138
139
140
141
# File 'lib/lvs/json_service/request.rb', line 135

def log_response(timing, body, options)
  if body.size < 1024 || options[:debug]
    LVS::JsonService::Logger.debug "Response (#{timing}): #{body.gsub(/\n/, '')}"
  else
    LVS::JsonService::Logger.debug "Response Snippet (#{timing} / #{"%.1f" % (body.size/1024)}kB): #{body.gsub(/\n/, '')[0..1024]}"
  end
end

#run_remote_request(service, args, options = {}) ⇒ Object



93
94
95
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
126
127
128
129
130
131
132
133
# File 'lib/lvs/json_service/request.rb', line 93

def run_remote_request(service, args, options = {})
  LVS::JsonService::Logger.debug "Requesting '#{service}' with #{args.to_json}"
  
  response             = nil
  result               = nil
  options[:request_id] = unique_request_id
  
  if options[:cached_for]
    timing = "CACHED"
    response, result = Rails.cache.read([service, args].cache_key, :expires_in => options[:cached_for])
  end
  if response.nil?
    start = Time.now
    http_standard_request_with_timeout(service, args, options) do |response|
      verify_request_id(response["X-LVS-Request-ID"], options[:request_id])
      net_timing = ("%.1f" % ((Time.now - start) * 1000)) + "ms"
      start = Time.now
      if options[:raw]
        result = response.body.force_encoding("UTF-8")
      else
        result = JSON.parse(response.body.force_encoding("UTF-8"))
      end
      parse_timing = ("%.1f" % ((Time.now - start) * 1000)) + "ms"
      timing = "Net: #{net_timing}, Parse: #{parse_timing}"
      if options[:cached_for]
        Rails.cache.write([service, args].cache_key, [response, result], :expires_in => options[:cached_for])
      end
      log_response(timing, response.body, options)
      if result.is_a?(Hash) && result.has_key?("PCode")
        raise LVS::JsonService::Error.new(result["message"], result["PCode"], service, args, result)
      end
      yield(result) if block_given?
    end
  else
    log_response(timing, response.body, options)
    if result.is_a?(Hash) && result.has_key?("PCode")
      raise LVS::JsonService::Error.new(result["message"], result["PCode"], service, args, result)
    end
  end
  result
end

#unique_request_idObject



15
16
17
# File 'lib/lvs/json_service/request.rb', line 15

def unique_request_id
  Digest::SHA1.hexdigest((rand(4294967295)+Time.now.usec).to_s)
end

#verify_request_id(returned_request_id, sent_request_id) ⇒ Object



143
144
145
146
147
148
149
150
# File 'lib/lvs/json_service/request.rb', line 143

def verify_request_id(returned_request_id, sent_request_id)
  if returned_request_id != sent_request_id && !returned_request_id.blank?
    raise LVS::JsonService::RequestMismatchError.new("The sent Request ID (#{sent_request_id}) didn't " + 
      "match the returned Request ID (#{returned_request_id}) ")
  else
    LVS::JsonService::Logger.debug "Sent and received Request ID - #{sent_request_id}"
  end
end