-
Notifications
You must be signed in to change notification settings - Fork 548
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Configurable HTTP client #313
Comments
This attempts to give some semblance of thread safety to parallel library requests by pre-assigning a certificate store, the initialization of which seems to be a weak point for thread safety. Note that while this does seem to empirically improve the situation, it doesn't guarantee actual thread safety. A longer term solution to the problem is probably to assign a per-thread HTTP client for much stronger guarantees, but this is a little further out. More discussion on that topic in #313. Fixes #382.
This attempts to give some semblance of thread safety to parallel library requests by pre-assigning a certificate store, the initialization of which seems to be a weak point for thread safety. Note that while this does seem to empirically improve the situation, it doesn't guarantee actual thread safety. A longer term solution to the problem is probably to assign a per-thread HTTP client for much stronger guarantees, but this is a little further out. More discussion on that topic in #313. Fixes #382.
Consider making Net::HTTP the default if going down this path. |
For what it's worth, rest-client 2.0 does support per-request proxies. The rest of it is definitely showing its age, though. Another option to consider might be to vendor whatever HTTP library is used. This would still break monkey patches, but might be faster to implement. Pros:
Cons:
|
@brandur I was wondering what the status is of this issue? Perhaps something like what the Basically provide a config option which is a proc that receives the Faraday builder. That way it's easy to enable for instance the instrumentation middleware. config.faraday = -> (f) { f.request(:instrumentation } |
@jensljungblad Oof, I hate to say it, but although this briefly became possible around V2 where you could reach into the library's default connection and modify Faraday options, it's now back to not possible as of V5 where we've once again dropped Faraday again. This issue is so old that we forgot to update it. Rather than a hyper-configurable connection/request, in general we've gone in the direction of opting for global-level configuration like Of course those still don't give any particularly easy instrumentation path. Possibly purely coincidentally, we got another request for something similar only an hour or so ago in this comment. I said in there that I think it might be a good idea to provide some callback "hooks" for various core operations that users could hook into. I haven't done anymore work into looking into that, but given that these days I'd prefer not to give access to any of the library's deeper HTTP internals (in case one day we want to say for example, add HTTP/2 support, and thus break everyone again), that sort of system seems like the natural evolution of the original feature described by this ticket. In the meantime, the public parts of |
Yeah, if there were some kind of hook around |
Bringing the context over from another PR here
Honestly, I'm not sure if it's relevant to configuring the http client directly, I think it's fine to be opinionated about that. In terms of adding hooks, we could take a stab at what an implimentation would look like. I really like what Faraday has done with its instrument module, reproduced here in entirety # frozen_string_literal: true
module Faraday
class Request
# Middleware for instrumenting Requests.
class Instrumentation < Faraday::Middleware
# Options class used in Request::Instrumentation class.
class Options < Faraday::Options.new(:name, :instrumenter)
# @return [String]
def name
self[:name] ||= 'request.faraday'
end
# @return [Class]
def instrumenter
self[:instrumenter] ||= ActiveSupport::Notifications
end
end
# Instruments requests using Active Support.
#
# Measures time spent only for synchronous requests.
#
# @example Using ActiveSupport::Notifications to measure time spent
# for Faraday requests.
# ActiveSupport::Notifications
# .subscribe('request.faraday') do |name, starts, ends, _, env|
# url = env[:url]
# http_method = env[:method].to_s.upcase
# duration = ends - starts
# $stderr.puts '[%s] %s %s (%.3f s)' %
# [url.host, http_method, url.request_uri, duration]
# end
# @param app [#call]
# @param options [nil, Hash] Options hash
# @option options [String] :name ('request.faraday')
# Name of the instrumenter
# @option options [Class] :instrumenter (ActiveSupport::Notifications)
# Active Support instrumenter class.
def initialize(app, options = nil)
super(app)
@name, @instrumenter = Options.from(options)
.values_at(:name, :instrumenter)
end
# @param env [Faraday::Env]
def call(env)
@instrumenter.instrument(@name, env) do
@app.call(env)
end
end
end
end
end Besides the object reference to ActiveSupport, we could do something along the lines of Stripe.instrumentation_handler = ActiveSupport::Notifications but we wouldn't have to declare activesupport as a dependency. If an instrumentation handler is set, we'd only have to declare the interface we expect it to receive and can use a mock for testing. Like with Faraday (even though it defaults to AS:N), we could expect whatever is set to this value to respond to #instrument, take a string name for the name of the event, and a set of unstructured data. We could then define standard instrumentation hooks, and pass in the raw Net::HTTP response in the unstructured data. https://edgeguides.rubyonrails.org/active_support_instrumentation.html That might be overkill, all our team is looking for is request instrumentation which we use for dashboards. But it'd allow us to avoid monkeypatching, and avoid adding dependency on ActiveSupport in the stripe ruby gem, while defining an easy interface that custom integrations can use, and one that works out of the box if the user is using rails or active support directly. AND we would only emit these events if WDYT? @brandur @jensljungblad |
For reference, this is how the HTTP gem's instrumentation feature is used: https://github.com/httprb/http/wiki/Logging-and-Instrumentation. |
I recently came across WeTransfer's measurometer via one of their other gems which seems close to @Senjai's idea. |
I just opened a PR for this: #870 |
It would be nice if we could plug in async-http. |
@ioquatix We don't have short term plans to add support for async-http for now but it's definitely something we've discussed before. Hopefully something we can introduce in the future! |
Add a mechanism for configuring an HTTP client that stripe-ruby will use. This is designed to solve such problems as:
This change is pseudo-breaking given that it will make significant changes to the plumbing of stripe-ruby and there's probably a fair number of people who are anchored to the current implementation through monkey patches and the like.
Replaces #124 and #219.
The text was updated successfully, but these errors were encountered: