@@ -2,27 +2,30 @@ module Emailable
22 class Client
33
44 def initialize
5- @client = Faraday . new ( 'https://api.emailable.com/v1' ) do |f |
6- f . request :url_encoded
7- f . response :json , content_type : /\b json$/
8- f . adapter :net_http_persistent
9- end
5+ @base_url = 'https://api.emailable.com/v1'
6+ @connection = create_connection ( URI ( @base_url ) )
107 end
118
12- def request ( method , endpoint , opts = { } )
9+ def request ( method , endpoint , params = { } )
1310 begin
14- tries ||= 0
11+ tries ||= 3
1512
16- @client . params [ :api_key ] = Emailable . api_key
13+ uri = URI ( "#{ @base_url } /#{ endpoint } " )
14+ params [ :api_key ] = Emailable . api_key
1715
18- response =
16+ http_response =
1917 if method == :get
20- @client . get ( endpoint , opts )
18+ uri . query = URI . encode_www_form ( params )
19+ @connection . get ( uri )
2120 elsif method == :post
22- @client . post ( endpoint , opts )
21+ request = Net ::HTTP ::Post . new ( uri , 'Content-Type' : 'application/json' )
22+ request . body = params . to_json
23+ @connection . request ( request )
2324 end
25+
26+ response = Response . new ( http_response )
2427 rescue => e
25- retry if self . class . should_retry? ( e , tries )
28+ retry if ( tries -= 1 ) > 0 && self . class . should_retry? ( e , tries )
2629
2730 raise e
2831 end
@@ -48,23 +51,59 @@ def request(method, endpoint, opts = {})
4851 raise error_map [ status . to_s ] . new ( error_attributes )
4952 end
5053
54+ private
55+
56+ def create_connection ( uri )
57+ connection = Net ::HTTP . new ( uri . host , uri . port )
58+
59+ # Time in seconds within which Net::HTTP will try to reuse an already
60+ # open connection when issuing a new operation. Outside this window, Ruby
61+ # will transparently close and re-open the connection without trying to
62+ # reuse it.
63+ #
64+ # Ruby's default of 2 seconds is almost certainly too short. Here I've
65+ # reused Go's default for `DefaultTransport`.
66+ connection . keep_alive_timeout = 30
67+
68+ connection . open_timeout = Emailable . open_timeout
69+ connection . read_timeout = Emailable . read_timeout
70+ if connection . respond_to? ( :write_timeout= )
71+ connection . write_timeout = Emailable . write_timeout
72+ end
73+ connection . use_ssl = uri . scheme == "https"
74+
75+ connection
76+ end
77+
5178 def self . should_retry? ( error , num_retries )
5279 return false if num_retries >= Emailable . max_network_retries
5380
54- # Retry on timeout-related problems (either on open or read).
55- return true if error . is_a? ( Faraday ::TimeoutError )
81+ case error
82+ when Net ::OpenTimeout , Net ::ReadTimeout
83+ # Retry on timeout-related problems (either on open or read).
84+ true
85+ when EOFError , Errno ::ECONNREFUSED , Errno ::ECONNRESET ,
86+ Errno ::EHOSTUNREACH , Errno ::ETIMEDOUT , SocketError
87+ # Destination refused the connection, the connection was reset, or a
88+ # variety of other connection failures. This could occur from a single
89+ # saturated server, so retry in case it's intermittent.
90+ true
91+ when Net ::HTTPError
92+ # 409 Conflict
93+ return true if error . http_status == 409
5694
57- # Destination refused the connection, the connection was reset, or a
58- # variety of other connection failures. This could occur from a single
59- # saturated server, so retry in case it's intermittent.
60- return true if error . is_a? ( Faraday ::ConnectionFailed )
95+ # 429 Too Many Requests
96+ return true if error . http_status == 429
6197
62- if error . is_a? ( Faraday ::ClientError ) && error . response
63- # 409 conflict
64- return true if error . response [ :status ] == 409
65- end
98+ # 500 Internal Server Error
99+ return true if error . http_status == 500
66100
67- false
101+ # 503 Service Unavailable
102+ error . http_status == 503
103+ else
104+ false
105+ end
68106 end
107+
69108 end
70109end
0 commit comments