Consider this begin-rescue-ensure block:
attempts=0
begin
make_service_call()
rescue Exception
retry unless attempts>2
exit -1
ensure
attemps += 1
ensure code is executed once, just before the code block exits and it will be called at that time.
But because of the unless attempts>2 condition, and the fact that ensure will only be called "just before the code exits" (e.g. due to exit -1) the attempts += 1 will not be executed, and so there is an infinite loop.
ensure is like __finally in C++ : you could catch the exception and then use a goto : but finally will not be called until the function is actually about to exit.