Skip to content

Commit 4072275

Browse files
authored
Add support for in_parallel. (#45)
1 parent 16d6ad1 commit 4072275

File tree

2 files changed

+99
-2
lines changed

2 files changed

+99
-2
lines changed

lib/async/http/faraday/adapter.rb

+56-2
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212

1313
require 'faraday'
1414
require 'faraday/adapter'
15+
16+
require 'async/barrier'
1517
require 'kernel/sync'
1618

1719
require 'async/http/client'
@@ -48,8 +50,47 @@ def read
4850
end
4951
end
5052

53+
class ParallelManager
54+
def initialize(options = {})
55+
@options = options
56+
@barrier = nil
57+
end
58+
59+
def run
60+
if $VERBOSE
61+
warn "Please update your Faraday version!", uplevel: 2
62+
end
63+
end
64+
65+
def async(&block)
66+
if @barrier
67+
@barrier.async(&block)
68+
else
69+
Sync(&block)
70+
end
71+
end
72+
73+
def execute(&block)
74+
Sync do
75+
@barrier = Async::Barrier.new
76+
77+
yield
78+
79+
@barrier.wait
80+
ensure
81+
@barrier&.stop
82+
end
83+
end
84+
end
85+
5186
# An adapter that allows Faraday to use Async::HTTP as the underlying HTTP client.
5287
class Adapter < ::Faraday::Adapter
88+
self.supports_parallel = true
89+
90+
def self.setup_parallel_manager(**options)
91+
ParallelManager.new(options)
92+
end
93+
5394
# The exceptions that are considered connection errors and result in a `Faraday::ConnectionFailed` exception.
5495
CONNECTION_EXCEPTIONS = [
5596
Errno::EADDRNOTAVAIL,
@@ -98,6 +139,21 @@ def call(env)
98139
# For compatibility with the default adapter:
99140
env.url.path = '/' if env.url.path.empty?
100141

142+
if parallel_manager = env.parallel_manager
143+
parallel_manager.async do
144+
perform_request(env)
145+
env.response.finish(env)
146+
end
147+
else
148+
perform_request(env)
149+
end
150+
151+
@app.call(env)
152+
end
153+
154+
private
155+
156+
def perform_request(env)
101157
with_client(env) do |endpoint, client|
102158
if body = env.body
103159
# We need to ensure the body is wrapped in a Readable object so that it can be read in chunks:
@@ -149,8 +205,6 @@ def call(env)
149205
raise ::Faraday::ConnectionFailed, e
150206
end
151207

152-
private
153-
154208
def with_client(env)
155209
Sync do
156210
endpoint = Endpoint.new(env.url)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
# frozen_string_literal: true
2+
3+
# Released under the MIT License.
4+
# Copyright, 2024, by Samuel Williams.
5+
6+
require 'async/http/faraday'
7+
8+
require 'sus/fixtures/async/reactor_context'
9+
require 'sus/fixtures/async/http/server_context'
10+
11+
describe Async::HTTP::Faraday::Adapter do
12+
with "a local http server" do
13+
include Sus::Fixtures::Async::ReactorContext
14+
include Sus::Fixtures::Async::HTTP::ServerContext
15+
16+
17+
let(:app) do
18+
Protocol::HTTP::Middleware.for do |request|
19+
Protocol::HTTP::Response[200, {}, ['Hello World']]
20+
end
21+
end
22+
23+
it "client can get resource" do
24+
adapter = Faraday.new(bound_url) do |builder|
25+
builder.adapter :async_http
26+
end
27+
28+
response1 = response2 = response3 = nil
29+
30+
adapter.in_parallel do
31+
response1 = adapter.get("/index")
32+
response2 = adapter.get("/index")
33+
response3 = adapter.get("/index")
34+
end
35+
36+
expect(response1.body).to be == 'Hello World'
37+
expect(response2.body).to be == 'Hello World'
38+
expect(response3.body).to be == 'Hello World'
39+
ensure
40+
adapter&.close
41+
end
42+
end
43+
end

0 commit comments

Comments
 (0)