recurly / recurly-client-ruby

A Ruby API wrapper for Recurly
https://developers.recurly.com
MIT License
180 stars 128 forks source link

Recurly::Errors::SSLError: SSL_read: unexpected eof while reading #893

Open drqCode opened 8 months ago

drqCode commented 8 months ago

Intermittent SSL Error is occurring when requesting Recurly service. Stack trace:

Recurly::Errors::SSLError: SSL_read: unexpected eof while reading
/usr/local/bundle/gems/recurly-4.47.0/lib/recurly/client.rb:230:in `rescue in block in run_request': SSL_read: unexpected eof while reading (Recurly::Errors::SSLError)
    from /usr/local/bundle/gems/recurly-4.47.0/lib/recurly/client.rb:180:in `block in run_request'
    from /usr/local/bundle/gems/recurly-4.47.0/lib/recurly/connection_pool.rb:21:in `with_connection'
    from /usr/local/bundle/gems/recurly-4.47.0/lib/recurly/client.rb:175:in `run_request'
    from /usr/local/bundle/gems/recurly-4.47.0/lib/recurly/client.rb:139:in `post'
    from /usr/local/bundle/gems/recurly-4.47.0/lib/recurly/client/operations.rb:4235:in `preview_purchase'
    from /usr/local/bundle/gems/actionpack-7.1.3.2/lib/action_controller/metal/basic_implicit_render.rb:6:in `send_action'
    from /usr/local/bundle/gems/actionpack-7.1.3.2/lib/abstract_controller/base.rb:224:in `process_action'
    from /usr/local/bundle/gems/ddtrace-1.20.0/lib/datadog/tracing/contrib/action_pack/action_controller/instrumentation.rb:105:in `process_action'
    from /usr/local/bundle/gems/actionpack-7.1.3.2/lib/action_controller/metal/rendering.rb:165:in `process_action'
    from /usr/local/bundle/gems/actionpack-7.1.3.2/lib/abstract_controller/callbacks.rb:259:in `block in process_action'
    from /usr/local/bundle/gems/activesupport-7.1.3.2/lib/active_support/callbacks.rb:121:in `block in run_callbacks'
    from /usr/local/bundle/gems/activesupport-7.1.3.2/lib/active_support/callbacks.rb:130:in `block in run_callbacks'
    from <internal:kernel>:133:in `then'
    from /usr/local/bundle/gems/activesupport-7.1.3.2/lib/active_support/callbacks.rb:130:in `block in run_callbacks'
    from /usr/local/bundle/gems/activesupport-7.1.3.2/lib/active_support/callbacks.rb:141:in `run_callbacks'
    from /usr/local/bundle/gems/actionpack-7.1.3.2/lib/abstract_controller/callbacks.rb:258:in `process_action'
    from /usr/local/bundle/gems/actionpack-7.1.3.2/lib/action_controller/metal/rescue.rb:25:in `process_action'
    from /usr/local/bundle/gems/actionpack-7.1.3.2/lib/action_controller/metal/instrumentation.rb:74:in `block in process_action'
    from /usr/local/bundle/gems/activesupport-7.1.3.2/lib/active_support/notifications.rb:206:in `block in instrument'
    from /usr/local/bundle/gems/activesupport-7.1.3.2/lib/active_support/notifications/instrumenter.rb:58:in `instrument'
    from /usr/local/bundle/gems/activesupport-7.1.3.2/lib/active_support/notifications.rb:206:in `instrument'
    from /usr/local/bundle/gems/actionpack-7.1.3.2/lib/action_controller/metal/instrumentation.rb:73:in `process_action'
    from /usr/local/bundle/gems/actionpack-7.1.3.2/lib/action_controller/metal/params_wrapper.rb:261:in `process_action'
    from /usr/local/bundle/gems/activerecord-7.1.3.2/lib/active_record/railties/controller_runtime.rb:32:in `process_action'
    from /usr/local/bundle/gems/actionpack-7.1.3.2/lib/abstract_controller/base.rb:160:in `process'
    from /usr/local/bundle/gems/actionpack-7.1.3.2/lib/action_controller/metal.rb:227:in `dispatch'
    from /usr/local/bundle/gems/actionpack-7.1.3.2/lib/action_controller/metal.rb:309:in `dispatch'
    from /usr/local/bundle/gems/actionpack-7.1.3.2/lib/action_dispatch/routing/route_set.rb:49:in `dispatch'
    from /usr/local/bundle/gems/actionpack-7.1.3.2/lib/action_dispatch/routing/route_set.rb:32:in `serve'
    from /usr/local/bundle/gems/actionpack-7.1.3.2/lib/action_dispatch/journey/router.rb:51:in `block in serve'
    from /usr/local/bundle/gems/actionpack-7.1.3.2/lib/action_dispatch/journey/router.rb:131:in `block in find_routes'
    from /usr/local/bundle/gems/actionpack-7.1.3.2/lib/action_dispatch/journey/router.rb:124:in `each'
    from /usr/local/bundle/gems/actionpack-7.1.3.2/lib/action_dispatch/journey/router.rb:124:in `find_routes'
    from /usr/local/bundle/gems/actionpack-7.1.3.2/lib/action_dispatch/journey/router.rb:32:in `serve'
    from /usr/local/bundle/gems/actionpack-7.1.3.2/lib/action_dispatch/routing/route_set.rb:882:in `call'
    from /usr/local/bundle/gems/rack-3.0.9.1/lib/rack/deflater.rb:47:in `call'
    from /usr/local/bundle/gems/rack-3.0.9.1/lib/rack/tempfile_reaper.rb:20:in `call'
    from /usr/local/bundle/gems/rack-3.0.9.1/lib/rack/etag.rb:29:in `call'
    from /usr/local/bundle/gems/rack-3.0.9.1/lib/rack/conditional_get.rb:31:in `call'
    from /usr/local/bundle/gems/rack-3.0.9.1/lib/rack/head.rb:15:in `call'
    from /usr/local/bundle/gems/actionpack-7.1.3.2/lib/action_dispatch/http/permissions_policy.rb:36:in `call'
    from /usr/local/bundle/gems/actionpack-7.1.3.2/lib/action_dispatch/http/content_security_policy.rb:33:in `call'
    from /usr/local/bundle/gems/rack-session-2.0.0/lib/rack/session/abstract/id.rb:272:in `context'
    from /usr/local/bundle/gems/rack-session-2.0.0/lib/rack/session/abstract/id.rb:266:in `call'
    from /usr/local/bundle/gems/actionpack-7.1.3.2/lib/action_dispatch/middleware/cookies.rb:689:in `call'
    from /usr/local/bundle/gems/actionpack-7.1.3.2/lib/action_dispatch/middleware/callbacks.rb:29:in `block in call'
    from /usr/local/bundle/gems/activesupport-7.1.3.2/lib/active_support/callbacks.rb:101:in `run_callbacks'
    from /usr/local/bundle/gems/actionpack-7.1.3.2/lib/action_dispatch/middleware/callbacks.rb:28:in `call'
    from /usr/local/bundle/gems/ddtrace-1.20.0/lib/datadog/tracing/contrib/rails/middlewares.rb:19:in `call'
    from /usr/local/bundle/gems/actionpack-7.1.3.2/lib/action_dispatch/middleware/debug_exceptions.rb:29:in `call'
    from /usr/local/bundle/gems/actionpack-7.1.3.2/lib/action_dispatch/middleware/show_exceptions.rb:31:in `call'
    from /usr/local/bundle/gems/lograge-0.14.0/lib/lograge/rails_ext/rack/logger.rb:18:in `call_app'
    from /usr/local/bundle/gems/railties-7.1.3.2/lib/rails/rack/logger.rb:26:in `call'
    from /usr/local/bundle/gems/actionpack-7.1.3.2/lib/action_dispatch/middleware/remote_ip.rb:92:in `call'
    from /usr/local/bundle/gems/request_store-1.5.1/lib/request_store/middleware.rb:19:in `call'
    from /usr/local/bundle/gems/actionpack-7.1.3.2/lib/action_dispatch/middleware/request_id.rb:28:in `call'
    from /usr/local/bundle/gems/rack-3.0.9.1/lib/rack/method_override.rb:28:in `call'
    from /usr/local/bundle/gems/rack-3.0.9.1/lib/rack/runtime.rb:24:in `call'
    from /usr/local/bundle/gems/rack-timeout-0.6.3/lib/rack/timeout/core.rb:148:in `block in call'
    from /usr/local/bundle/gems/rack-timeout-0.6.3/lib/rack/timeout/support/timeout.rb:19:in `timeout'
    from /usr/local/bundle/gems/rack-timeout-0.6.3/lib/rack/timeout/core.rb:147:in `call'
    from /usr/local/bundle/gems/activesupport-7.1.3.2/lib/active_support/cache/strategy/local_cache_middleware.rb:29:in `call'
    from /usr/local/bundle/gems/actionpack-7.1.3.2/lib/action_dispatch/middleware/executor.rb:14:in `call'
    from /usr/local/bundle/gems/actionpack-7.1.3.2/lib/action_dispatch/middleware/static.rb:25:in `call'
    from /usr/local/bundle/gems/rack-3.0.9.1/lib/rack/sendfile.rb:114:in `call'
    from /usr/local/bundle/gems/rack-heartbeat-1.1.0/lib/rack/heartbeat.rb:45:in `call'
    from /usr/local/bundle/gems/rack-cors-2.0.2/lib/rack/cors.rb:102:in `call'
    from /usr/local/bundle/gems/ddtrace-1.20.0/lib/datadog/tracing/contrib/rack/middlewares.rb:109:in `call'
    from /usr/local/bundle/gems/railties-7.1.3.2/lib/rails/engine.rb:536:in `call'
    from /usr/local/bundle/gems/puma-6.4.2/lib/puma/configuration.rb:272:in `call'
    from /usr/local/bundle/gems/puma-6.4.2/lib/puma/request.rb:100:in `block in handle_request'
    from /usr/local/bundle/gems/puma-6.4.2/lib/puma/thread_pool.rb:378:in `with_force_shutdown'
    from /usr/local/bundle/gems/puma-6.4.2/lib/puma/request.rb:99:in `handle_request'
    from /usr/local/bundle/gems/puma-6.4.2/lib/puma/server.rb:464:in `process_client'
    from /usr/local/bundle/gems/puma-6.4.2/lib/puma/server.rb:245:in `block in run'
    from /usr/local/bundle/gems/puma-6.4.2/lib/puma/thread_pool.rb:155:in `block in spawn_thread'
/usr/local/lib/ruby/3.3.0/openssl/buffering.rb:211:in `sysread_nonblock': SSL_read: unexpected eof while reading (OpenSSL::SSL::SSLError)
    from /usr/local/lib/ruby/3.3.0/openssl/buffering.rb:211:in `read_nonblock'
    from /usr/local/lib/ruby/3.3.0/net/protocol.rb:218:in `rbuf_fill'
    from /usr/local/lib/ruby/3.3.0/net/protocol.rb:199:in `readuntil'
    from /usr/local/lib/ruby/3.3.0/net/protocol.rb:209:in `readline'
    from /usr/local/lib/ruby/3.3.0/net/http/response.rb:158:in `read_status_line'
    from /usr/local/lib/ruby/3.3.0/net/http/response.rb:147:in `read_new'
    from /usr/local/lib/ruby/3.3.0/net/http.rb:2342:in `block in transport_request'
    from /usr/local/lib/ruby/3.3.0/net/http.rb:2333:in `catch'
    from /usr/local/lib/ruby/3.3.0/net/http.rb:2333:in `transport_request'
    from /usr/local/lib/ruby/3.3.0/net/http.rb:2306:in `request'
    from /usr/local/bundle/gems/recurly-4.47.0/lib/recurly/client.rb:196:in `block in run_request'
    from /usr/local/bundle/gems/recurly-4.47.0/lib/recurly/connection_pool.rb:21:in `with_connection'
    from /usr/local/bundle/gems/recurly-4.47.0/lib/recurly/client.rb:175:in `run_request'
    from /usr/local/bundle/gems/recurly-4.47.0/lib/recurly/client.rb:139:in `post'
    from /usr/local/bundle/gems/recurly-4.47.0/lib/recurly/client/operations.rb:4235:in `preview_purchase'
    from /usr/local/bundle/gems/ddtrace-1.20.0/lib/datadog/tracing/trace_operation.rb:199:in `block in measure'
    from /usr/local/bundle/gems/ddtrace-1.20.0/lib/datadog/tracing/span_operation.rb:150:in `measure'
    from /usr/local/bundle/gems/ddtrace-1.20.0/lib/datadog/tracing/trace_operation.rb:199:in `measure'
    from /usr/local/bundle/gems/ddtrace-1.20.0/lib/datadog/tracing/tracer.rb:385:in `start_span'
    from /usr/local/bundle/gems/ddtrace-1.20.0/lib/datadog/tracing/tracer.rb:159:in `block in trace'
    from /usr/local/bundle/gems/ddtrace-1.20.0/lib/datadog/tracing/context.rb:45:in `activate!'
    from /usr/local/bundle/gems/ddtrace-1.20.0/lib/datadog/tracing/tracer.rb:158:in `trace'
    from /usr/local/bundle/gems/ddtrace-1.20.0/lib/datadog/tracing.rb:18:in `trace'
    from <internal:kernel>:90:in `tap'
    from /usr/local/bundle/gems/usecasing-0.1.10/lib/usecasing/base.rb:40:in `block in tx'
    from /usr/local/bundle/gems/usecasing-0.1.10/lib/usecasing/base.rb:37:in `each'
    from /usr/local/bundle/gems/usecasing-0.1.10/lib/usecasing/base.rb:37:in `tx'
    from /usr/local/bundle/gems/actionpack-7.1.3.2/lib/action_controller/metal/basic_implicit_render.rb:6:in `send_action'
    from /usr/local/bundle/gems/actionpack-7.1.3.2/lib/abstract_controller/base.rb:224:in `process_action'
    from /usr/local/bundle/gems/ddtrace-1.20.0/lib/datadog/tracing/contrib/action_pack/action_controller/instrumentation.rb:105:in `process_action'
    from /usr/local/bundle/gems/actionpack-7.1.3.2/lib/action_controller/metal/rendering.rb:165:in `process_action'
    from /usr/local/bundle/gems/actionpack-7.1.3.2/lib/abstract_controller/callbacks.rb:259:in `block in process_action'
    from /usr/local/bundle/gems/activesupport-7.1.3.2/lib/active_support/callbacks.rb:121:in `block in run_callbacks'
    from /usr/local/bundle/gems/activesupport-7.1.3.2/lib/active_support/callbacks.rb:130:in `block in run_callbacks'
    from <internal:kernel>:133:in `then'
    from /usr/local/bundle/gems/activesupport-7.1.3.2/lib/active_support/callbacks.rb:130:in `block in run_callbacks'
    from /usr/local/bundle/gems/activesupport-7.1.3.2/lib/active_support/callbacks.rb:141:in `run_callbacks'
    from /usr/local/bundle/gems/actionpack-7.1.3.2/lib/abstract_controller/callbacks.rb:258:in `process_action'
    from /usr/local/bundle/gems/actionpack-7.1.3.2/lib/action_controller/metal/rescue.rb:25:in `process_action'
    from /usr/local/bundle/gems/actionpack-7.1.3.2/lib/action_controller/metal/instrumentation.rb:74:in `block in process_action'
    from /usr/local/bundle/gems/activesupport-7.1.3.2/lib/active_support/notifications.rb:206:in `block in instrument'
    from /usr/local/bundle/gems/activesupport-7.1.3.2/lib/active_support/notifications/instrumenter.rb:58:in `instrument'
    from /usr/local/bundle/gems/activesupport-7.1.3.2/lib/active_support/notifications.rb:206:in `instrument'
    from /usr/local/bundle/gems/actionpack-7.1.3.2/lib/action_controller/metal/instrumentation.rb:73:in `process_action'
    from /usr/local/bundle/gems/actionpack-7.1.3.2/lib/action_controller/metal/params_wrapper.rb:261:in `process_action'
    from /usr/local/bundle/gems/activerecord-7.1.3.2/lib/active_record/railties/controller_runtime.rb:32:in `process_action'
    from /usr/local/bundle/gems/actionpack-7.1.3.2/lib/abstract_controller/base.rb:160:in `process'
    from /usr/local/bundle/gems/actionpack-7.1.3.2/lib/action_controller/metal.rb:227:in `dispatch'
    from /usr/local/bundle/gems/actionpack-7.1.3.2/lib/action_controller/metal.rb:309:in `dispatch'
    from /usr/local/bundle/gems/actionpack-7.1.3.2/lib/action_dispatch/routing/route_set.rb:49:in `dispatch'
    from /usr/local/bundle/gems/actionpack-7.1.3.2/lib/action_dispatch/routing/route_set.rb:32:in `serve'
    from /usr/local/bundle/gems/actionpack-7.1.3.2/lib/action_dispatch/journey/router.rb:51:in `block in serve'
    from /usr/local/bundle/gems/actionpack-7.1.3.2/lib/action_dispatch/journey/router.rb:131:in `block in find_routes'
    from /usr/local/bundle/gems/actionpack-7.1.3.2/lib/action_dispatch/journey/router.rb:124:in `each'
    from /usr/local/bundle/gems/actionpack-7.1.3.2/lib/action_dispatch/journey/router.rb:124:in `find_routes'
    from /usr/local/bundle/gems/actionpack-7.1.3.2/lib/action_dispatch/journey/router.rb:32:in `serve'
    from /usr/local/bundle/gems/actionpack-7.1.3.2/lib/action_dispatch/routing/route_set.rb:882:in `call'
    from /usr/local/bundle/gems/rack-3.0.9.1/lib/rack/deflater.rb:47:in `call'
    from /usr/local/bundle/gems/rack-3.0.9.1/lib/rack/tempfile_reaper.rb:20:in `call'
    from /usr/local/bundle/gems/rack-3.0.9.1/lib/rack/etag.rb:29:in `call'
    from /usr/local/bundle/gems/rack-3.0.9.1/lib/rack/conditional_get.rb:31:in `call'
    from /usr/local/bundle/gems/rack-3.0.9.1/lib/rack/head.rb:15:in `call'
    from /usr/local/bundle/gems/actionpack-7.1.3.2/lib/action_dispatch/http/permissions_policy.rb:36:in `call'
    from /usr/local/bundle/gems/actionpack-7.1.3.2/lib/action_dispatch/http/content_security_policy.rb:33:in `call'
    from /usr/local/bundle/gems/rack-session-2.0.0/lib/rack/session/abstract/id.rb:272:in `context'
    from /usr/local/bundle/gems/rack-session-2.0.0/lib/rack/session/abstract/id.rb:266:in `call'
    from /usr/local/bundle/gems/actionpack-7.1.3.2/lib/action_dispatch/middleware/cookies.rb:689:in `call'
    from /usr/local/bundle/gems/actionpack-7.1.3.2/lib/action_dispatch/middleware/callbacks.rb:29:in `block in call'
    from /usr/local/bundle/gems/activesupport-7.1.3.2/lib/active_support/callbacks.rb:101:in `run_callbacks'
    from /usr/local/bundle/gems/actionpack-7.1.3.2/lib/action_dispatch/middleware/callbacks.rb:28:in `call'
    from /usr/local/bundle/gems/ddtrace-1.20.0/lib/datadog/tracing/contrib/rails/middlewares.rb:19:in `call'
    from /usr/local/bundle/gems/actionpack-7.1.3.2/lib/action_dispatch/middleware/debug_exceptions.rb:29:in `call'
    from /usr/local/bundle/gems/actionpack-7.1.3.2/lib/action_dispatch/middleware/show_exceptions.rb:31:in `call'
    from /usr/local/bundle/gems/lograge-0.14.0/lib/lograge/rails_ext/rack/logger.rb:18:in `call_app'
    from /usr/local/bundle/gems/railties-7.1.3.2/lib/rails/rack/logger.rb:26:in `call'
    from /usr/local/bundle/gems/actionpack-7.1.3.2/lib/action_dispatch/middleware/remote_ip.rb:92:in `call'
    from /usr/local/bundle/gems/request_store-1.5.1/lib/request_store/middleware.rb:19:in `call'
    from /usr/local/bundle/gems/actionpack-7.1.3.2/lib/action_dispatch/middleware/request_id.rb:28:in `call'
    from /usr/local/bundle/gems/rack-3.0.9.1/lib/rack/method_override.rb:28:in `call'
    from /usr/local/bundle/gems/rack-3.0.9.1/lib/rack/runtime.rb:24:in `call'
    from /usr/local/bundle/gems/rack-timeout-0.6.3/lib/rack/timeout/core.rb:148:in `block in call'
    from /usr/local/bundle/gems/rack-timeout-0.6.3/lib/rack/timeout/support/timeout.rb:19:in `timeout'
    from /usr/local/bundle/gems/rack-timeout-0.6.3/lib/rack/timeout/core.rb:147:in `call'
    from /usr/local/bundle/gems/activesupport-7.1.3.2/lib/active_support/cache/strategy/local_cache_middleware.rb:29:in `call'
    from /usr/local/bundle/gems/actionpack-7.1.3.2/lib/action_dispatch/middleware/executor.rb:14:in `call'
    from /usr/local/bundle/gems/actionpack-7.1.3.2/lib/action_dispatch/middleware/static.rb:25:in `call'
    from /usr/local/bundle/gems/rack-3.0.9.1/lib/rack/sendfile.rb:114:in `call'
    from /usr/local/bundle/gems/rack-heartbeat-1.1.0/lib/rack/heartbeat.rb:45:in `call'
    from /usr/local/bundle/gems/rack-cors-2.0.2/lib/rack/cors.rb:102:in `call'
    from /usr/local/bundle/gems/ddtrace-1.20.0/lib/datadog/tracing/contrib/rack/middlewares.rb:109:in `call'
    from /usr/local/bundle/gems/railties-7.1.3.2/lib/rails/engine.rb:536:in `call'
    from /usr/local/bundle/gems/puma-6.4.2/lib/puma/configuration.rb:272:in `call'
    from /usr/local/bundle/gems/puma-6.4.2/lib/puma/request.rb:100:in `block in handle_request'
    from /usr/local/bundle/gems/puma-6.4.2/lib/puma/thread_pool.rb:378:in `with_force_shutdown'
    from /usr/local/bundle/gems/puma-6.4.2/lib/puma/request.rb:99:in `handle_request'
    from /usr/local/bundle/gems/puma-6.4.2/lib/puma/server.rb:464:in `process_client'
    from /usr/local/bundle/gems/puma-6.4.2/lib/puma/server.rb:245:in `block in run'
    from /usr/local/bundle/gems/puma-6.4.2/lib/puma/thread_pool.rb:155:in `block in spawn_thread'

Note: Some trace lines were removed due to sec policies.

This started once we upgraded the base docker image from ruby:3.3.0-slim-bullseye to ruby:3.3.0-slim-bookworm.

Your Environment

douglasmiller commented 8 months ago

@drqCode,

I threw together this simple script and it ran successfully inside of the ruby:3.3.0-slim-bookworm container. I do not think that your issue is caused by a limitation of the ruby client library or Recurly API.

Script:

require 'recurly'

client = Recurly::Client.new(api_key: ENV['RECURLY_API_KEY'])

sites = client.list_sites
sites.each do |site|
  puts "Site: #{site.mode}"
end

Execution:

└[$]›docker run -it --rm -e RECURLY_API_KEY=$RECURLY_API_KEY -v $(pwd):/app -w /app ruby:3.3.0-slim-bookworm bash -c "bundle && bundle exec ruby container-test.rb"
Fetching gem metadata from https://rubygems.org/.............
Fetching recurly 4.47.0
Installing recurly 4.47.0
Bundle complete! 1 Gemfile dependency, 2 gems now installed.
Use `bundle info [gemname]` to see where a bundled gem is installed.
/usr/local/bundle/gems/recurly-4.47.0/lib/recurly/client.rb:4: warning: base64 was loaded from the standard library, but will no longer be part of the default gems since Ruby 3.4.0. Add base64 to your Gemfile or gemspec. Also contact author of recurly-4.47.0 to add base64 into its gemspec.
Site: sandbox
drqCode commented 8 months ago

The error happens intermittently and not often. The behavior is very like this: https://github.com/redis/redis-rb/issues/1106. I will debug on this more, but so far everything points to this gem where it uses persistent HTTP connections, but it does not gracefully handle those SSL EOF while reading errors. Note that between bullseye and bookworm, OpenSSL is upraded from 1.1.1 to 3.0.9.

drqCode commented 7 months ago

@douglasmiller we still experience that issue. The issue seems to be this: https://github.com/openssl/openssl/discussions/22690. I couldn't reproduce this via a script yet. It happens regularly on a clustered puma prod app, but we managed to overcome the error by patching the keep_alive_timeout in gem's connection pool:

module Recurly
  class ConnectionPool
    def init_http_connection(uri, ca_file)
      http = Net::HTTP.new(uri.host, uri.port)
      http.use_ssl = uri.scheme == 'https'
      http.ca_file = ca_file
      http.verify_mode = OpenSSL::SSL::VERIFY_PEER
      http.keep_alive_timeout = 10 # lowering the timeout avoids the error

      http
    end
  end
end

My assumption is that Recurly server does not close connections properly in certain conditions. By setting a lower keep alive the client will close connection before the server may get that chance.

drqCode commented 2 months ago

@douglasmiller The issue still persists. Did you try to reproduce it? You should use a client instance and try to requests spanned over a couple of minutes.