Skip to content

Commit 58d45b6

Browse files
committed
fix: avoid duplicate requests in pooled requester
1 parent 487a574 commit 58d45b6

File tree

5 files changed

+82
-3
lines changed

5 files changed

+82
-3
lines changed

Gemfile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,5 @@ end
1414
group :test do
1515
gem "aruba", "~> 2.3"
1616
gem "webmock", "~> 3.25"
17+
gem "webrick", "~> 1.8"
1718
end

exa-ai-ruby.gemspec

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,4 +37,5 @@ Gem::Specification.new do |spec|
3737
spec.add_development_dependency "rubocop", "~> 1.64"
3838
spec.add_development_dependency "aruba", "~> 2.2"
3939
spec.add_development_dependency "webmock", "~> 3.23"
40+
spec.add_development_dependency "webrick", "~> 1.8"
4041
end

lib/exa/internal/transport/pooled_net_requester.rb

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,16 @@ def execute(request)
4747
end
4848

4949
_, response = enum.next
50-
body = Exa::Internal::Util.fused_enum(enum)
50+
body_stream = Enumerator.new do |y|
51+
loop do
52+
begin
53+
y << enum.next
54+
rescue StopIteration
55+
break
56+
end
57+
end
58+
end
59+
body = Exa::Internal::Util.fused_enum(body_stream)
5160
[Integer(response.code), response, body]
5261
end
5362
end

lib/exa/responses/search_response.rb

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ class SearchResponse < T::Struct
88
const :search_type, T.nilable(String)
99
const :results, T::Array[ResultWithContent]
1010
const :context, T.nilable(String)
11-
const :cost_dollars, T.nilable(Float)
11+
const :cost_dollars, T.nilable(T.any(Float, T::Hash[Symbol, T.untyped]))
1212

1313
def self.from_hash(hash)
1414
sym = Helpers.symbolize_keys(hash)
@@ -18,9 +18,22 @@ def self.from_hash(hash)
1818
search_type: sym[:searchType],
1919
results: Array(sym[:results]).map { ResultWithContent.from_hash(_1) },
2020
context: sym[:context],
21-
cost_dollars: sym[:costDollars]&.to_f
21+
cost_dollars: normalize_cost(sym[:costDollars])
2222
)
2323
end
24+
25+
def self.normalize_cost(value)
26+
case value
27+
when nil
28+
nil
29+
when Numeric
30+
value.to_f
31+
when Hash
32+
Exa::Responses::Helpers.symbolize_keys(value)
33+
else
34+
value
35+
end
36+
end
2437
end
2538

2639
class FindSimilarResponse < T::Struct
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
# frozen_string_literal: true
2+
3+
require "test_helper"
4+
require "webrick"
5+
6+
class PooledNetRequesterTest < Minitest::Test
7+
def setup
8+
@server = nil
9+
@server_thread = nil
10+
end
11+
12+
def teardown
13+
@server&.shutdown
14+
@server_thread&.join
15+
end
16+
17+
def test_single_http_request_per_execute_call
18+
requests = Queue.new
19+
port = free_port
20+
@server = WEBrick::HTTPServer.new(
21+
Port: port,
22+
BindAddress: "127.0.0.1",
23+
Logger: WEBrick::Log.new(File::NULL),
24+
AccessLog: []
25+
)
26+
@server.mount_proc "/echo" do |req, res|
27+
requests << req.body
28+
res.status = 200
29+
res["Content-Type"] = "application/json"
30+
res.body = {ok: true}.to_json
31+
end
32+
@server_thread = Thread.new { @server.start }
33+
34+
requester = Exa::Internal::Transport::PooledNetRequester.new(size: 1)
35+
client = Exa::Client.new(
36+
api_key: "test-key",
37+
base_url: "http://127.0.0.1:#{port}",
38+
requester: requester
39+
)
40+
41+
response = client.request(method: :post, path: "echo", body: {hello: "world"})
42+
assert_equal({ok: true}, response)
43+
44+
assert_equal 1, requests.length, "expected a single HTTP request but multiple were made"
45+
end
46+
47+
private
48+
49+
def free_port
50+
server = TCPServer.new("127.0.0.1", 0)
51+
port = server.addr[1]
52+
server.close
53+
port
54+
end
55+
end

0 commit comments

Comments
 (0)