Class: Helio::HelioClient
- Inherits:
-
Object
- Object
- Helio::HelioClient
- Defined in:
- lib/helio/helio_client.rb
Overview
HelioClient executes requests against the Helio API and allows a user to recover both a resource a call returns as well as a response object that contains information on the HTTP call.
Defined Under Namespace
Classes: RequestLogContext, SystemProfiler
Instance Attribute Summary collapse
-
#conn ⇒ Object
Returns the value of attribute conn.
Class Method Summary collapse
- .active_client ⇒ Object
- .default_client ⇒ Object
-
.default_conn ⇒ Object
A default Faraday connection to be used when one isn’t configured.
-
.should_retry?(e, num_retries) ⇒ Boolean
Checks if an error is a problem that we should retry on.
- .sleep_time(num_retries) ⇒ Object
Instance Method Summary collapse
- #execute_request(method, path, api_base: nil, api_id: nil, api_token: nil, headers: {}, params: {}) ⇒ Object
-
#initialize(conn = nil) ⇒ HelioClient
constructor
Initializes a new HelioClient.
-
#request ⇒ Object
Executes the API call within the given block.
Constructor Details
#initialize(conn = nil) ⇒ HelioClient
Initializes a new HelioClient. Expects a Faraday connection object, and uses a default connection unless one is passed.
12 13 14 15 |
# File 'lib/helio/helio_client.rb', line 12 def initialize(conn = nil) self.conn = conn || self.class.default_conn @system_profiler = SystemProfiler.new end |
Instance Attribute Details
#conn ⇒ Object
Returns the value of attribute conn.
8 9 10 |
# File 'lib/helio/helio_client.rb', line 8 def conn @conn end |
Class Method Details
.active_client ⇒ Object
17 18 19 |
# File 'lib/helio/helio_client.rb', line 17 def self.active_client Thread.current[:helio_client] || default_client end |
.default_client ⇒ Object
21 22 23 |
# File 'lib/helio/helio_client.rb', line 21 def self.default_client Thread.current[:helio_client_default_client] ||= HelioClient.new(default_conn) end |
.default_conn ⇒ Object
A default Faraday connection to be used when one isn’t configured. This object should never be mutated, and instead instantiating your own connection and wrapping it in a HelioClient object should be preferred.
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 |
# File 'lib/helio/helio_client.rb', line 28 def self.default_conn # We're going to keep connections around so that we can take advantage # of connection re-use, so make sure that we have a separate connection # object per thread. Thread.current[:helio_client_default_conn] ||= begin conn = Faraday.new do |c| c.use Faraday::Request::Multipart c.use Faraday::Request::UrlEncoded c.use Faraday::Response::RaiseError c.adapter Faraday.default_adapter end if Helio.verify_ssl_certs conn.ssl.verify = true conn.ssl.cert_store = Helio.ca_store else conn.ssl.verify = false unless @verify_ssl_warned @verify_ssl_warned = true $stderr.puts("WARNING: Running without SSL cert verification. " \ "You should never do this in production. " \ "Execute 'Helio.verify_ssl_certs = true' to enable verification.") end end conn end end |
.should_retry?(e, num_retries) ⇒ Boolean
Checks if an error is a problem that we should retry on. This includes both socket errors that may represent an intermittent problem and some special HTTP statuses.
61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 |
# File 'lib/helio/helio_client.rb', line 61 def self.should_retry?(e, num_retries) return false if num_retries >= Helio.max_network_retries # Retry on timeout-related problems (either on open or read). return true if e.is_a?(Faraday::TimeoutError) # Destination refused the connection, the connection was reset, or a # variety of other connection failures. This could occur from a single # saturated server, so retry in case it's intermittent. return true if e.is_a?(Faraday::ConnectionFailed) if e.is_a?(Faraday::ClientError) && e.response # 409 conflict return true if e.response[:status] == 409 end false end |
.sleep_time(num_retries) ⇒ Object
80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 |
# File 'lib/helio/helio_client.rb', line 80 def self.sleep_time(num_retries) # Apply exponential backoff with initial_network_retry_delay on the # number of num_retries so far as inputs. Do not allow the number to exceed # max_network_retry_delay. sleep_seconds = [Helio.initial_network_retry_delay * (2**(num_retries - 1)), Helio.max_network_retry_delay].min # Apply some jitter by randomizing the value in the range of (sleep_seconds # / 2) to (sleep_seconds). sleep_seconds *= (0.5 * (1 + rand)) # But never sleep less than the base sleep seconds. sleep_seconds = [Helio.initial_network_retry_delay, sleep_seconds].max sleep_seconds end |
Instance Method Details
#execute_request(method, path, api_base: nil, api_id: nil, api_token: nil, headers: {}, params: {}) ⇒ Object
114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 |
# File 'lib/helio/helio_client.rb', line 114 def execute_request(method, path, api_base: nil, api_id: nil, api_token: nil, headers: {}, params: {}) api_base ||= Helio.api_base api_id ||= Helio.api_id api_token ||= Helio.api_token check_api_token!(api_token) params = Util.objects_to_ids(params) url = api_url(path, api_base) body = nil query_params = nil case method.to_s.downcase.to_sym when :get, :head, :delete query_params = params else body = if headers[:content_type] && headers[:content_type] == "multipart/form-data" params else Util.encode_parameters(params) end end headers = request_headers(api_token, method) .update(Util.normalize_headers(headers)) # stores information on the request we're about to make so that we don't # have to pass as many parameters around for logging. context = RequestLogContext.new context.api_id = headers["X-API-ID"] context.api_token = api_token context.api_version = headers["Helio-Version"] context.body = body context.idempotency_key = headers["Idempotency-Key"] context.method = method context.path = path context.query_params = query_params ? Util.encode_parameters(query_params) : nil http_resp = execute_request_with_rescues(api_base, context) do conn.run_request(method, url, body, headers) do |req| req..open_timeout = Helio.open_timeout req..timeout = Helio.read_timeout req.params = query_params unless query_params.nil? end end begin resp = HelioResponse.from_faraday_response(http_resp) rescue JSON::ParserError raise general_api_error(http_resp.status, http_resp.body) end # Allows HelioClient#request to return a response object to a caller. @last_response = resp [resp, api_token] end |
#request ⇒ Object
Executes the API call within the given block. Usage looks like:
client = HelioClient.new
charge, resp = client.request { Charge.create }
101 102 103 104 105 106 107 108 109 110 111 112 |
# File 'lib/helio/helio_client.rb', line 101 def request @last_response = nil old_helio_client = Thread.current[:helio_client] Thread.current[:helio_client] = self begin res = yield [res, @last_response] ensure Thread.current[:helio_client] = old_helio_client end end |