🎓 A1Learner
🔍
0 of 46 lessons completed

Elixir Backoff Strategies

Backoff is a waiting plan where the delay before the next try grows after each failure. Growing delays give a failing service room to recover instead of being hit again at once.

Exponential delays double each time

The base delay is 100. Each next delay doubles, so the four delays are 100, 200, 400, and 800.

defmodule Backoff do
  def delay(n), do: 100 * Integer.pow(2, n)
end
delays = Enum.map_join([0, 1, 2, 3], ", ", fn n -> Integer.to_string(Backoff.delay(n)) end)
IO.puts("delays: #{delays}")

A cap stops growth at a maximum

The cap is 1000. Growth stops at the cap, so later delays stay at 1000.

defmodule Backoff do
  def delay(n), do: min(100 * Integer.pow(2, n), 1000)
end
delays = Enum.map_join([0, 1, 2, 3, 4, 5], ", ", fn n -> Integer.to_string(Backoff.delay(n)) end)
IO.puts("delays: #{delays}")

A growing plan passes a fixed plan

A fixed plan repeats the same delay every time. A growing plan starts smaller and passes the fixed delay on the fourth try.

defmodule Backoff do
  def delay(n), do: 100 * Integer.pow(2, n)
end
fixed = Enum.map_join([0, 1, 2, 3], ", ", fn _n -> "500" end)
growing = Enum.map_join([0, 1, 2, 3], ", ", fn n -> Integer.to_string(Backoff.delay(n)) end)
IO.puts("fixed: #{fixed}")
IO.puts("growing: #{growing}")

Example

defmodule Backoff do
  def delay(n), do: min(100 * Integer.pow(2, n), 1000)
end
failures = 2
delays = Enum.map(0..(failures - 1), fn n -> Backoff.delay(n) end)
delay_text = Enum.map_join(delays, ", ", fn n -> Integer.to_string(n) end)
outcomes = [:error, :error, :ok]
result = List.last(outcomes)
IO.puts("delays: #{delay_text}")
IO.puts("total planned wait: #{Enum.sum(delays)}")
IO.puts("result: #{result}")

Key points

  • Delay: the waiting time before the next try.
  • Exponential growth: each delay doubles the one before it.
  • Base delay: the first delay, used when the exponent is zero.
  • Cap: the largest delay allowed, which stops growth from running away.
  • Computed value: the delay is a number that can be worked out in advance, without waiting.

In this example, a job fails twice and then succeeds. The plan gives delays of 100 and 200 for the two failures, which add up to a total planned wait of 300. The last outcome is ok, so the job ends in success after the planned delays.

Note

a delay value is not a pause, since the plan can be checked without pausing the program.

Try it Yourself

Edit the code, then press Run.

Running is simulated

Exercise

A plan has a base delay of 100 and a cap of 1000. What delay does it give for attempt 4?