Class: Stripe::ConnectionManager
- Inherits:
-
Object
- Object
- Stripe::ConnectionManager
- Defined in:
- lib/stripe/connection_manager.rb
Overview
Manages connections across multiple hosts which is useful because the library may connect to multiple hosts during a typical session (main API, Connect, Uploads). Ruby doesn’t provide an easy way to make this happen easily, so this class is designed to track what we’re connected to and manage the lifecycle of those connections.
Note that this class in itself is not thread safe. We expect it to be instantiated once per thread.
Instance Attribute Summary collapse
-
#config ⇒ Object
readonly
Returns the value of attribute config.
-
#last_used ⇒ Object
readonly
Timestamp (in seconds procured from the system’s monotonic clock) indicating when the connection manager last made a request.
Instance Method Summary collapse
-
#clear ⇒ Object
Finishes any active connections by closing their TCP connection and clears them from internal tracking.
-
#connection_for(uri) ⇒ Object
Gets a connection for a given URI.
-
#execute_request(method, uri, body: nil, headers: nil, query: nil, &block) ⇒ Object
Executes an HTTP request to the given URI with the given method.
-
#initialize(config = Stripe.config) ⇒ ConnectionManager
constructor
A new instance of ConnectionManager.
Constructor Details
#initialize(config = Stripe.config) ⇒ ConnectionManager
Returns a new instance of ConnectionManager.
20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
# File 'lib/stripe/connection_manager.rb', line 20 def initialize(config = Stripe.config) @config = config @active_connections = {} @last_used = Util.monotonic_time # A connection manager may be accessed across threads as one thread makes # requests on it while another is trying to clear it (either because it's # trying to garbage collect the manager or trying to clear it because a # configuration setting has changed). That's probably thread-safe already # because of Ruby's GIL, but just in case the library's running on JRuby # or the like, use a mutex to synchronize access in this connection # manager. @mutex = Mutex.new end |
Instance Attribute Details
#config ⇒ Object (readonly)
Returns the value of attribute config.
18 19 20 |
# File 'lib/stripe/connection_manager.rb', line 18 def config @config end |
#last_used ⇒ Object (readonly)
Timestamp (in seconds procured from the system’s monotonic clock) indicating when the connection manager last made a request. This is used by ‘APIRequestor` to determine whether a connection manager should be garbage collected or not.
17 18 19 |
# File 'lib/stripe/connection_manager.rb', line 17 def last_used @last_used end |
Instance Method Details
#clear ⇒ Object
Finishes any active connections by closing their TCP connection and clears them from internal tracking.
37 38 39 40 41 42 43 44 |
# File 'lib/stripe/connection_manager.rb', line 37 def clear @mutex.synchronize do @active_connections.each do |_, connection| connection.finish end @active_connections = {} end end |
#connection_for(uri) ⇒ Object
Gets a connection for a given URI. This is for internal use only as it’s subject to change (we’ve moved between HTTP client schemes in the past and may do it again).
‘uri` is expected to be a string.
51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 |
# File 'lib/stripe/connection_manager.rb', line 51 def connection_for(uri) @mutex.synchronize do u = URI.parse(uri) connection = @active_connections[[u.host, u.port]] if connection.nil? connection = create_connection(u) connection.start @active_connections[[u.host, u.port]] = connection end connection end end |
#execute_request(method, uri, body: nil, headers: nil, query: nil, &block) ⇒ Object
Executes an HTTP request to the given URI with the given method. Also allows a request body, headers, and query string to be specified.
69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 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 134 |
# File 'lib/stripe/connection_manager.rb', line 69 def execute_request(method, uri, body: nil, headers: nil, query: nil, &block) # Perform some basic argument validation because it's easy to get # confused between strings and hashes for things like body and query # parameters. raise ArgumentError, "method should be a symbol" \ unless method.is_a?(Symbol) raise ArgumentError, "uri should be a string" \ unless uri.is_a?(String) raise ArgumentError, "body should be a string" \ if body && !body.is_a?(String) raise ArgumentError, "headers should be a hash" \ if headers && !headers.is_a?(Hash) raise ArgumentError, "query should be a string" \ if query && !query.is_a?(String) @last_used = Util.monotonic_time connection = connection_for(uri) u = URI.parse(uri) path = if query u.path + "?" + query else u.path end method_name = method.to_s.upcase has_response_body = method_name != "HEAD" request = Net::HTTPGenericRequest.new( method_name, (body ? true : false), has_response_body, path, headers ) Util.log_debug("ConnectionManager starting request", method_name: method_name, path: path, process_id: Process.pid, thread_object_id: Thread.current.object_id, connection_manager_object_id: object_id, connection_object_id: connection.object_id, log_timestamp: Util.monotonic_time) resp = @mutex.synchronize do # The block parameter is special here. If a block is provided, the block # is invoked with the Net::HTTPResponse. However, the body will not have # been read yet in the block, and can be streamed by calling # HTTPResponse#read_body. connection.request(request, body, &block) end Util.log_debug("ConnectionManager request complete", method_name: method_name, path: path, process_id: Process.pid, thread_object_id: Thread.current.object_id, connection_manager_object_id: object_id, connection_object_id: connection.object_id, response_object_id: resp.object_id, log_timestamp: Util.monotonic_time) resp end |