Skip to content

Commit 0a68530

Browse files
authored
feat: use native interrupt support in Downloads.jl (#82)
Detect if we are using a newer version of Download.jl that supports interrupting of requests natively and use that instead of throwing `InterruptException`. ref: JuliaLang/Downloads.jl#256 and JuliaLang/Downloads.jl#259 fixes: #81
1 parent 2d44798 commit 0a68530

File tree

2 files changed

+38
-5
lines changed

2 files changed

+38
-5
lines changed

Project.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ keywords = ["Swagger", "OpenAPI", "REST"]
44
license = "MIT"
55
desc = "OpenAPI server and client helper for Julia"
66
authors = ["JuliaHub Inc."]
7-
version = "0.1.25"
7+
version = "0.1.26"
88

99
[deps]
1010
Base64 = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f"

src/client.jl

+37-4
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,7 @@ struct Client
151151
escape_path_params::Union{Nothing,Bool}
152152
chunk_reader_type::Union{Nothing,Type{<:AbstractChunkReader}}
153153
long_polling_timeout::Int
154+
request_interrupt_supported::Bool
154155

155156
function Client(root::String;
156157
headers::Dict{String,String}=Dict{String,String}(),
@@ -174,7 +175,8 @@ struct Client
174175
# disable ALPN to support servers that enable both HTTP/2 and HTTP/1.1 on same port
175176
Downloads.Curl.setopt(easy, LibCURL.CURLOPT_SSL_ENABLE_ALPN, 0)
176177
end
177-
new(root, headers, get_return_type, clntoptions, downloader, Ref{Int}(timeout), pre_request_hook, escape_path_params, chunk_reader_type, long_polling_timeout)
178+
interruptable = request_supports_interrupt()
179+
new(root, headers, get_return_type, clntoptions, downloader, Ref{Int}(timeout), pre_request_hook, escape_path_params, chunk_reader_type, long_polling_timeout, interruptable)
178180
end
179181
end
180182

@@ -556,6 +558,10 @@ function do_request(ctx::Ctx, stream::Bool=false; stream_to::Union{Channel,Nothi
556558

557559
try
558560
if stream
561+
interrupt = nothing
562+
if ctx.client.request_interrupt_supported
563+
kwargs[:interrupt] = interrupt = Base.Event()
564+
end
559565
@sync begin
560566
download_task = @async begin
561567
try
@@ -565,7 +571,10 @@ function do_request(ctx::Ctx, stream::Bool=false; stream_to::Union{Channel,Nothi
565571
kwargs...
566572
)
567573
catch ex
568-
if !isa(ex, InterruptException)
574+
# If request method does not support interrupt natively, InterrptException is used to
575+
# signal the download task to stop. Otherwise, InterrptException is not handled and is rethrown.
576+
# Any exception other than InterruptException is rethrown always.
577+
if ctx.client.request_interrupt_supported || !isa(ex, InterruptException)
569578
@error("exception invoking request", exception=(ex,catch_backtrace()))
570579
rethrow()
571580
end
@@ -604,10 +613,25 @@ function do_request(ctx::Ctx, stream::Bool=false; stream_to::Union{Channel,Nothi
604613
catch ex
605614
isa(ex, InvalidStateException) || rethrow(ex)
606615
interrupted = true
607-
istaskdone(download_task) || schedule(download_task, InterruptException(), error=true)
616+
if !istaskdone(download_task)
617+
# If the download task is still running, interrupt it.
618+
# If it supports interrupt natively, then use event to signal it.
619+
# Otherwise, throw an InterruptException to stop the download task.
620+
if ctx.client.request_interrupt_supported
621+
notify(interrupt)
622+
else
623+
schedule(download_task, InterruptException(), error=true)
624+
end
625+
end
626+
end
627+
end
628+
if !interrupted && !istaskdone(download_task)
629+
if ctx.client.request_interrupt_supported
630+
notify(interrupt)
631+
else
632+
schedule(download_task, InterruptException(), error=true)
608633
end
609634
end
610-
interrupted || istaskdone(download_task) || schedule(download_task, InterruptException(), error=true)
611635
end
612636
end
613637
else
@@ -863,4 +887,13 @@ function deep_object_serialize(dict::Dict, parent_key::String = "")
863887
return Dict(parts)
864888
end
865889

890+
function request_supports_interrupt()
891+
for m in methods(request)
892+
if :interrupt in Base.kwarg_decl(m)
893+
return true
894+
end
895+
end
896+
return false
897+
end
898+
866899
end # module Clients

0 commit comments

Comments
 (0)