Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Updates for retry changes in 0.6. #368

Merged
merged 2 commits into from
Sep 12, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,8 @@ Currently, the `@compat` macro supports the following syntaxes:

* There are versions of `InexactError`, `DomainError`, and `OverflowError` that take the same arguments as introduced in Julia 0.7-DEV ([#20005], [#22751], [#22761]).

* `retry` for the more flexible `retry` method introduced in 0.6 which includes support for kwargs ([#19331], [#21419]).

## Renamed functions


Expand Down
57 changes: 57 additions & 0 deletions src/Compat.jl
Original file line number Diff line number Diff line change
Expand Up @@ -140,8 +140,65 @@ macro compat(ex...)
esc(_compat(ex[1]))
end


export @compat

if VERSION < v"0.6.0-dev.2042"
immutable ExponentialBackOff
n::Int
first_delay::Float64
max_delay::Float64
factor::Float64
jitter::Float64

function ExponentialBackOff(n, first_delay, max_delay, factor, jitter)
all(x->x>=0, (n, first_delay, max_delay, factor, jitter)) || error("all inputs must be non-negative")
new(n, first_delay, max_delay, factor, jitter)
end
end

"""
ExponentialBackOff(; n=1, first_delay=0.05, max_delay=10.0, factor=5.0, jitter=0.1)

A [`Float64`](@ref) iterator of length `n` whose elements exponentially increase at a
rate in the interval `factor` * (1 ± `jitter`). The first element is
`first_delay` and all elements are clamped to `max_delay`.
"""
ExponentialBackOff(; n=1, first_delay=0.05, max_delay=10.0, factor=5.0, jitter=0.1) =
ExponentialBackOff(n, first_delay, max_delay, factor, jitter)
Base.start(ebo::ExponentialBackOff) = (ebo.n, min(ebo.first_delay, ebo.max_delay))
function Base.next(ebo::ExponentialBackOff, state)
next_n = state[1]-1
curr_delay = state[2]
next_delay = min(ebo.max_delay, state[2] * ebo.factor * (1.0 - ebo.jitter + (rand() * 2.0 * ebo.jitter)))
(curr_delay, (next_n, next_delay))
end
Base.done(ebo::ExponentialBackOff, state) = state[1]<1
Base.length(ebo::ExponentialBackOff) = ebo.n

function retry(f::Function; delays=ExponentialBackOff(), check=nothing)
(args...; kwargs...) -> begin
state = start(delays)
while true
try
return f(args...; kwargs...)
catch e
done(delays, state) && rethrow(e)
if check !== nothing
state, retry_or_not = check(state, e)
retry_or_not || rethrow(e)
end
end
(delay, state) = next(delays, state)
sleep(delay)
end
end
end
else
import Base.ExponentialBackOff
import Base.retry
end

import Base: redirect_stdin, redirect_stdout, redirect_stderr
if VERSION < v"0.6.0-dev.374"
for (F,S) in ((:redirect_stdin, :STDIN), (:redirect_stdout, :STDOUT), (:redirect_stderr, :STDERR))
Expand Down
47 changes: 47 additions & 0 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,53 @@ cd(dirwalk) do
end
rm(dirwalk, recursive=true)

let
# Subset of tests copied from base test/error.jl
function foo_error(c, n)
c[1] += 1
if c[1] <= n
error("foo")
end
return 7
end

# Success on first attempt
c = [0]
@test Compat.retry(foo_error)(c, 0) == 7
@test c[1] == 1

# Success on second attempt
c = [0]
@test Compat.retry(foo_error)(c,1) == 7
@test c[1] == 2

# 2 failed retry attempts, so exception is raised
c = [0]
ex = try
Compat.retry(foo_error, delays=Compat.ExponentialBackOff(n=2))(c, 3)
catch e
e
end

c = [0]
ex = try
Compat.retry(
foo_error,
check=(s,e)->(s, try e.http_status_code == "503" end != true)
)(c, 2)
catch e
e
end
@test typeof(ex) == ErrorException
@test ex.msg == "foo"
@test c[1] == 2

# Functions with keyword arguments
foo_kwargs(x; y=5) = x + y
@test Compat.retry(foo_kwargs)(3) == 8
@test Compat.retry(foo_kwargs)(3; y=4) == 7
end

for os in [:apple, :bsd, :linux, :unix, :windows]
from_base = if VERSION >= v"0.7.0-DEV.914"
Expr(:., Expr(:., :Base, Base.Meta.quot(:Sys)), Base.Meta.quot(Symbol("is", os)))
Expand Down