Apero.Retry (Apero v2.1.0)

Copy Markdown View Source

Retry with exponential backoff and optional jitter.

Example

Apero.Retry.with(
  fn -> HTTPoison.get(url) end,
  max_attempts: 5,
  base_delay: 100,
  max_delay: 5_000,
  retry_on: fn
    {:ok, %{status: status}} when status >= 500 -> true
    {:error, %HTTPoison.Error{reason: :timeout}} -> true
    _ -> false
  end
)

Summary

Functions

Handles a {:apero_retry, ...} message produced by schedule_next/7. Runs the next attempt; if it succeeds or exhausts retries, returns the result via {:apero_retry_done, result}. Otherwise schedules the next retry.

Non-blocking variant of with/2 that uses Process.send_after between attempts instead of Process.sleep.

Types

predicate()

@type predicate() :: (any() -> boolean())

Functions

handle_message(arg)

@spec handle_message(
  {:apero_retry, (-> any()), integer(), integer(), integer(), integer(),
   (any() -> boolean()), (-> any())}
) :: any()

Handles a {:apero_retry, ...} message produced by schedule_next/7. Runs the next attempt; if it succeeds or exhausts retries, returns the result via {:apero_retry_done, result}. Otherwise schedules the next retry.

This is the GenServer hook for non-blocking retry.

schedule_next(fun, attempt, max, base, max_d, should_retry?, on_retry)

@spec schedule_next(
  (-> any()),
  integer(),
  integer(),
  integer(),
  integer(),
  (any() -> boolean()),
  (-> any())
) :: :ok

Non-blocking variant of with/2 that uses Process.send_after between attempts instead of Process.sleep.

Caveats

Because the retry is driven by the calling process's mailbox, this helper must be called from a process that can receive messages (typically a GenServer). The calling process should be ready to receive the {:apero_retry_continue, fun, state} message; in practice this helper is best used from a custom handle_info/2 that calls the next attempt and sends itself another message after the delay.

Most consumers should prefer the simpler with/2 (which uses Process.sleep) unless they are calling from a GenServer mailbox loop.

with(fun, opts \\ [])

@spec with(
  (-> any()),
  keyword()
) :: any()