From 67477d610f6e71eba8a09c880b2ca7e526c2b485 Mon Sep 17 00:00:00 2001 From: Sascha Wolke Date: Sat, 13 Jul 2019 17:47:57 +0200 Subject: [PATCH] Reuse Patron session with mutex Reuse Patron session to support keep-alive/connection reuse and make them thread-safe using a mutex. fixes #1001 --- docs/adapters/patron.md | 6 ++++++ lib/faraday/adapter/patron.rb | 24 +++++++++++++++++++++--- spec/faraday/adapter/patron_spec.rb | 17 +++++++++++++++++ 3 files changed, 44 insertions(+), 3 deletions(-) diff --git a/docs/adapters/patron.md b/docs/adapters/patron.md index 97a22d6d9..edd2e17a3 100644 --- a/docs/adapters/patron.md +++ b/docs/adapters/patron.md @@ -18,6 +18,12 @@ conn = Faraday.new(...) do |f| end ``` +## Multithreading + +This adapter use a mutex around the patron session to be thread-safe. +A [connection_pool](https://rubygems.org/gems/connection_pool) can be +used to share multiple connections between threads. + ## Links * [Gem RDoc][rdoc] diff --git a/lib/faraday/adapter/patron.rb b/lib/faraday/adapter/patron.rb index 3020dcf4b..6869754e7 100644 --- a/lib/faraday/adapter/patron.rb +++ b/lib/faraday/adapter/patron.rb @@ -6,13 +6,25 @@ class Adapter class Patron < Faraday::Adapter dependency 'patron' + def initialize(app = nil, opts = {}, &block) + @mutex = Mutex.new + super(app, opts, &block) + end + def call(env) - super + # Patron::Session is not thread-safe, use a mutex to be safe + @mutex.synchronize do + super + perform_request env + end + end + + def perform_request(env) # TODO: support streaming requests env[:body] = env[:body].read if env[:body].respond_to? :read - session = ::Patron::Session.new - @config_block&.call(session) + session = @session ||= create_session + if (env[:url].scheme == 'https') && env[:ssl] configure_ssl(session, env[:ssl]) end @@ -83,6 +95,12 @@ def call(env) end end + def create_session + session = ::Patron::Session.new + @config_block&.call(session) + session + end + def configure_ssl(session, ssl) if ssl.fetch(:verify, true) session.cacert = ssl[:ca_file] diff --git a/spec/faraday/adapter/patron_spec.rb b/spec/faraday/adapter/patron_spec.rb index 812fd1a06..cbd5a9be1 100644 --- a/spec/faraday/adapter/patron_spec.rb +++ b/spec/faraday/adapter/patron_spec.rb @@ -15,4 +15,21 @@ expect { conn.get('/') }.to raise_error(RuntimeError, 'Configuration block called') end + + it 'reuses the patron session for keep-alive' do + last_session = nil + conn = Faraday.new do |f| + f.adapter :patron do |session| + if last_session + expect(session).to eq last_session + else + last_session = session + end + end + end + + stub_request(:get, 'http://example.com') + conn.get('http://example.com/') + conn.get('http://example.com/') + end end