Packages

Amazon States Language workflow interpreter.

Current section

Files

Jump to
workflows lib workflows retrier.ex
Raw

lib/workflows/retrier.ex

defmodule Workflows.Retrier do
@moduledoc """
Implements a state retrier.
## References
* https://states-language.net/#errors
"""
@type t :: term()
defstruct [:error_equals, :interval_seconds, :max_attempts, :backoff_rate, :attempt]
@default_interval_seconds 1
@default_max_attempts 3
@default_backoff_rate 2.0
@doc """
Create a new Retrier.
"""
@spec create(any()) :: {:ok, t()} | {:error, term()}
def create(%{"ErrorEquals" => errors} = attrs) do
interval_seconds = Map.get(attrs, "IntervalSeconds", @default_interval_seconds)
max_attempts = Map.get(attrs, "MaxAttempts", @default_max_attempts)
backoff_rate = Map.get(attrs, "BackoffRate", @default_backoff_rate)
do_create(errors, interval_seconds, max_attempts, backoff_rate)
end
def create(_attrs) do
{:error, :missing_error_equals}
end
def next(%__MODULE__{attempt: attempt, max_attempts: max_attempts} = retrier)
when attempt < max_attempts do
wait = retrier.interval_seconds + retrier.backoff_rate * attempt
{:wait, wait, %__MODULE__{retrier | attempt: attempt + 1}}
end
def next(retrier), do: {:max_attempts, retrier}
defp do_create([], _interval_seconds, _max_attempts, _backoff_rate),
do: {:error, "ErrorEquals must be non empty"}
defp do_create(_errors, interval_seconds, _max_attempts, _backoff_rate)
when not is_integer(interval_seconds)
when interval_seconds <= 0,
do: {:error, "IntervalSeconds must be a positive integer"}
defp do_create(_errors, _interval_seconds, max_attempts, _backoff_rate)
when not is_integer(max_attempts)
when max_attempts < 0,
do: {:error, "MaxAttempts must be a non-negative integer"}
defp do_create(_errors, _interval_seconds, _max_attempts, backoff_rate)
when backoff_rate < 1.0,
do: {:error, "BackoffRate must be a greater than or equal to 1.0"}
defp do_create(errors, interval_seconds, max_attempts, backoff_rate) do
retrier = %__MODULE__{
error_equals: errors,
interval_seconds: interval_seconds,
max_attempts: max_attempts,
backoff_rate: backoff_rate,
attempt: 0
}
{:ok, retrier}
end
end