Ruby Retry and Ensure
ensure runs a closing step whatever happened inside a begin block. retry runs the block again, and a counter keeps it from looping forever.
ensure runs either way
The first block divides with no trouble, and the second block divides by zero and is rescued. The ensure line prints at the end of both blocks.
begin
total = 10 / 2
puts total
ensure
puts "First block closed"
end
begin
total = 10 / 0
puts total
rescue ZeroDivisionError
puts "Divided by zero"
ensure
puts "Second block closed"
endretry with a counter
The attempts counter sits outside the block and grows on each run. The raise fires on the first two tries, so retry runs the block until the third try works.
attempts = 0
begin
attempts += 1
puts "Try #{attempts}"
if attempts < 3
raise "Not ready"
end
puts "Worked"
rescue
retry
endretry inside a method
The run_job method holds its rescue line with no begin line. The state hash counts the tries, and the guard stops retry once the count reaches 3.
def run_job(state)
state[:tries] += 1
puts "Try #{state[:tries]}"
if state[:tries] < 2
raise "Still warming up"
end
puts "Job done"
rescue
if state[:tries] < 3
retry
end
puts "Job gave up"
end
state = {tries: 0}
run_job(state)ensure inside a method
The divide method rescues a zero division and returns 0 for it. The ensure line prints at the end of each call, success or failure.
def divide(a, b)
a / b
rescue ZeroDivisionError
puts "Divided by zero"
0
ensure
puts "Divide call over"
end
puts divide(10, 2)
puts divide(10, 0)Example
attempts = 0
begin
attempts += 1
if attempts < 3
raise "Server busy"
end
puts "Loaded on try #{attempts}"
rescue
retry
ensure
puts "Loading finished"
endKey points
- ensure runs after the begin part, error or no error.
- ensure runs after a rescue line has handled an error.
- retry sends control back to the start of the begin part.
- A counter outside the block can count the tries across retries.
- retry in a rescue line gives the block another run.
- A method body acts as its own block, so rescue and retry can sit in a method with no begin line.
In this example, the block raises Server busy on the first two tries and the rescue line sends it back with retry. The counter reaches 3 on the third run, the block prints its loaded line, and ensure prints the closing line once at the very end.
Note
An unbounded retry loops forever, so every retry needs a stopping count.
Try it Yourself
Edit the code, then press Run.
Running is simulated
Exercise
A begin block raises an error, a rescue line handles it, and the block also has an ensure line. When does the ensure part run?