Skip to content

Commit

Permalink
Work around for JuliaLang/julia#19979
Browse files Browse the repository at this point in the history
Retry.jl used to use try/catch inside the catch block's "@ignore if ..."
condition. The purpose of this was to treat if conditions that throw
errors as false. e.f. @ignore if e.reason == "Foo" end might throw an
exception if e does not have a reason field. Retry.jl used to allow this
and treat it as false.

At present doing a nested try/catch in a catch block causes the Julia
stacktrace to be corrupted: JuliaLang/julia#19979 (comment)

After this commit, Retry.jl not requires @ignore if conditions to return
true or false and not throw exceptions.

The ecode() function has been exported to allow replacing

    @ignore if e.code == "404" end

with

    @ignore if ecode(e) == "404" end
  • Loading branch information
samoconnor committed Nov 21, 2017
1 parent 2d80a29 commit 6c565a3
Show file tree
Hide file tree
Showing 4 changed files with 37 additions and 29 deletions.
7 changes: 6 additions & 1 deletion src/Retry.jl
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
module Retry

export @repeat, @protected
__precompile__(true)

export @repeat, @protected, efield, ecode

efield(x, f, default=nothing) = f in fieldnames(x) ? getfield(x, f) : default
ecode(x) = efield(x, :code)

include("repeat_try.jl")
include("protected_try.jl")
Expand Down
1 change: 0 additions & 1 deletion src/protected_try.jl
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,6 @@ macro protected(try_expr::Expr)

if_expr = check_macro_if(expr)
(condition, action) = if_expr.args
if_expr.args[1] = :(try $condition catch false end)

# Clear exception variable at end of "@ignore if..." block...
push!(action.args, :($exception = nothing))
Expand Down
34 changes: 19 additions & 15 deletions src/repeat_try.jl
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,9 @@ end

function esc_args!(expr::Expr)
for (i, arg) in enumerate(expr.args)
expr.args[i] = esc(arg)
if isa(arg, Symbol) || arg.head != :line
expr.args[i] = esc(arg)
end
end
end

Expand All @@ -140,11 +142,8 @@ macro repeat(max, try_expr::Expr)
esc_args!(try_expr)
try_expr.args[3] = catch_block

# Check for nothing exception at start of catch block...
unshift!(catch_block.args, :($exception == nothing && rethrow($exception)))

# Rethrow at end of catch block...
push!(catch_block.args, :($exception == nothing || rethrow($exception)))
max = esc(max)
exception = esc(exception)

for (i, expr) in enumerate(catch_block.args)

Expand All @@ -159,25 +158,24 @@ macro repeat(max, try_expr::Expr)

if_expr = check_macro_if(expr)
(condition, action) = if_expr.args
if_expr.args[1] = :(try $(esc(condition)) catch e false end)
if_expr.args[1] = esc(condition)
esc_args!(action)

# Clear exception variable at end of "@ignore if..." block...
if handler == "@ignore"
push!(action.args, :($exception = nothing))
push!(action.args, :(ignore = true))
end

esc_args!(action)

# Loop to try again at end of "@retry if..." block...
if handler == "@retry"
push!(action.args, :(if i < $(esc(max)) continue end))
push!(action.args, :(if i < $max continue end))
end

# Add exponentially increasing delay with random jitter,
# and loop to try again at end of "@delay_retry if..." block...
if handler == "@delay_retry"
push!(action.args, quote
if i < $(esc(max))
if i < $max
sleep(delay * (0.8 + (0.4 * rand())))
delay *= 10
continue
Expand All @@ -187,17 +185,24 @@ macro repeat(max, try_expr::Expr)

# Replace @ignore/@retry macro call with modified if expression...
catch_block.args[i] = if_expr
else
elseif expr.head != :line
catch_block.args[i] = esc(expr)
end
end

# Check for nothing exception at start of catch block...
insert!(catch_block.args, 2, :($exception == nothing && rethrow()))
unshift!(catch_block.args, :(ignore = false))

# Rethrow at end of catch block...
push!(catch_block.args, :(ignore || rethrow($exception)))

# Build retry expression...
quote
delay = 0.05
result = false

for i in 1:$(esc(max))
for i in 1:$max
result = $try_expr
break
end
Expand All @@ -207,7 +212,6 @@ macro repeat(max, try_expr::Expr)
end



#==============================================================================#
# End of file.
#==============================================================================#
24 changes: 12 additions & 12 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ end
@test_throws TestException @protected try
throw(TestException(7))
catch e
@ignore if e.code == "Nothing to see here" end
@ignore if ecode(e) == "Nothing to see here" end
end


Expand All @@ -38,7 +38,7 @@ end
@test @protected try
throw(TestException(7))
catch e
@ignore if e.code == 7 end
@ignore if ecode(e) == 7 end
end


Expand All @@ -58,7 +58,7 @@ count = 0
global count += 1
throw(TestException(7))
catch e
@retry if e.code == 7 end
@retry if ecode(e) == 7 end
end
@test count == 4

Expand All @@ -70,7 +70,7 @@ count = 0
global count += 1
throw(TestException(5))
catch e
@retry if e.code == 7 end
@retry if ecode(e) == 7 end
end
@test count == 1

Expand All @@ -82,7 +82,7 @@ count = 0
global count += 1
throw(TestException(7))
catch e
@ignore if e.code == 7 end
@ignore if ecode(e) == 7 end
end
@test count == 1

Expand All @@ -102,7 +102,7 @@ i = -1
count += 1
throw(TestException(7))
catch e
@delay_retry if e.code == 7 end
@delay_retry if ecode(e) == 7 end
end
@test count == 3

Expand All @@ -118,8 +118,8 @@ count = 0
global count += 1
throw(TestException(count))
catch e
@retry if e.code < 3 end
@ignore if e.code == 3 end
@retry if ecode(e) < 3 end
@ignore if ecode(e) == 3 end
end
@test count == 2

Expand All @@ -131,8 +131,8 @@ count = 0
global count += 1
throw(TestException(count))
catch e
@retry if e.code < 3 end
@ignore if e.code == 3 end
@retry if ecode(e) < 3 end
@ignore if ecode(e) == 3 end
end
@test count == 3

Expand All @@ -144,8 +144,8 @@ count = 0
global count += 1
throw(TestException(count))
catch e
@retry if e.code < 3 end
@ignore if e.code == 3 end
@retry if ecode(e) < 3 end
@ignore if ecode(e) == 3 end
end
@test count == 3

Expand Down

0 comments on commit 6c565a3

Please sign in to comment.