Skip to content

Commit 3dbb25f

Browse files
committed
Add test and forcenew option to avoid socket closing race condition
1 parent dca6572 commit 3dbb25f

File tree

3 files changed

+25
-8
lines changed

3 files changed

+25
-8
lines changed

src/ConnectionPool.jl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -351,13 +351,15 @@ function newconnection(::Type{T},
351351
host::AbstractString,
352352
port::AbstractString;
353353
connection_limit=default_connection_limit[],
354+
forcenew::Bool=false,
354355
idle_timeout=typemax(Int),
355356
require_ssl_verification::Bool=NetworkOptions.verify_host(host, "SSL"),
356357
kw...)::Connection where {T <: IO}
357358
return acquire(
358359
POOL,
359360
(T, host, port, require_ssl_verification, true);
360361
max_concurrent_connections=Int(connection_limit),
362+
forcenew=forcenew,
361363
idle_timeout=Int(idle_timeout)) do
362364
Connection(host, port,
363365
idle_timeout, require_ssl_verification,

src/connectionpools.jl

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -93,12 +93,12 @@ call the provided function `f()`, which must return a new connection instance of
9393
This new connection instance will be tracked by the `Pod` and MUST be returned to the `Pod`
9494
after use by calling `release(pod, conn)`.
9595
"""
96-
function acquire(f, pod::Pod)
96+
function acquire(f, pod::Pod, forcenew::Bool=false)
9797
lock(pod.lock)
9898
try
9999
# if there are idle connections in the pod,
100100
# let's check if they're still valid and can be used again
101-
while !isempty(pod.conns)
101+
while !forcenew && !isempty(pod.conns)
102102
# Pod connections are FIFO, so grab the earliest returned connection
103103
# println("$(taskid()): checking idle_timeout connections for reuse")
104104
conn = popfirst!(pod.conns)
@@ -126,7 +126,7 @@ function acquire(f, pod::Pod)
126126
# is notified
127127
# println("$(taskid()): connection pool maxxed out; waiting for connection to be released to the pod")
128128
conn = wait(pod.lock)
129-
if conn !== nothing
129+
if !forcenew && conn !== nothing
130130
# println("$(taskid()): checking recently released connection validity for reuse")
131131
if isvalid(pod, conn)
132132
return trackconnection!(pod, conn)
@@ -242,11 +242,11 @@ created and passed the `max`, `idle_timeout`, and `reuse` keyword arguments if p
242242
The provided function `f` must create a new connection instance of type `C`.
243243
The acquired connection MUST be returned to the pool by calling `release(pool, key, conn)` exactly once.
244244
"""
245-
function acquire(f, pool::Pool{C}, key; kw...) where {C}
245+
function acquire(f, pool::Pool{C}, key; forcenew::Bool=false, kw...) where {C}
246246
pod = lock(pool.lock) do
247247
get!(() -> Pod(C; kw...), pool.pods, key)
248248
end
249-
return acquire(f, pod)
249+
return acquire(f, pod, forcenew)
250250
end
251251

252252
function acquire(pool::Pool{C}, key, conn::C; kw...) where {C}

test/client.jl

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -525,15 +525,30 @@ end
525525
seekstart(req_body)
526526
resp = HTTP.get("http://localhost:8080/retry"; body=req_body, response_stream=res_body, retry=false, status_exception=false)
527527
@test String(take!(res_body)) == "500 unexpected error"
528+
# even if status_exception=true, we should still get the right response body
529+
shouldfail[] = true
530+
seekstart(req_body)
531+
try
532+
resp = HTTP.get("http://localhost:8080/retry"; body=req_body, response_stream=res_body, retry=false, forcenew=true)
533+
catch e
534+
@test e isa HTTP.StatusError
535+
@test e.status == 500
536+
@test String(take!(res_body)) == "500 unexpected error"
537+
end
528538
# don't throw a 500, but set status to status we don't retry by default
529539
shouldfail[] = false
530540
status[] = 404
531541
seekstart(req_body)
532542
check = (s, ex, req, resp) -> begin
533-
@test String(resp.body) == "404 unexpected error"
534-
resp.status == 404
543+
str = String(resp.body)
544+
if str != "404 unexpected error" || resp.status != 404
545+
@error "unexpected response body" str
546+
return false
547+
end
548+
@test str == "404 unexpected error"
549+
return resp.status == 404
535550
end
536-
resp = HTTP.get("http://localhost:8080/retry"; body=req_body, response_stream=res_body, retry_check=(s, ex, req, resp) -> resp.status == 404)
551+
resp = HTTP.get("http://localhost:8080/retry"; body=req_body, response_stream=res_body, retry_check=check)
537552
@test isok(resp)
538553
@test String(take!(res_body)) == "hey there sailor"
539554
finally

0 commit comments

Comments
 (0)