Retry with capped jittered backoff in Crystal

Crystal
require "random"

def retry_with_backoff(max_attempts = 5, base = 0.1, cap = 2.0)
  attempt = 0
  begin
    attempt += 1
    yield
  rescue ex
    raise ex if attempt >= max_attempts
    backoff = base * Math.pow(2.0, (attempt - 1).to_f)
    sleep (Math.min(cap, backoff) * (0.5 + Random.rand)).seconds
    retry
  end
end

retry_with_backoff(3) { puts "attempt" }