# `Jitter`
[🔗](https://github.com/ivan-podgurskiy/jitter/blob/v0.1.0/lib/jitter.ex#L1)

Backoff jitter strategies based on Marc Brooker's
"Exponential Backoff and Jitter" (AWS Architecture Blog, 2015).

# `apply_equal`

```elixir
@spec apply_equal(
  Enumerable.t(),
  keyword()
) :: Enumerable.t()
```

Applies Equal Jitter to an existing delay stream.

Each delay in the input enumerable is capped at `:cap` and then split in half:
the result is the half plus a uniform random value in `[0, half]`. Compatible
with `Retry.DelayStreams.exponential_backoff/0`:

    import Retry.DelayStreams
    exponential_backoff() |> Jitter.apply_equal(cap: 30_000) |> Stream.take(5)

## Examples

    iex> [100, 200, 400, 800, 2000]
    ...> |> Jitter.apply_equal(cap: 1000, rng: fn _min, max -> max end)
    ...> |> Enum.to_list()
    [100, 200, 400, 800, 1000]

    iex> [100, 200, 400, 800, 2000]
    ...> |> Jitter.apply_equal(cap: 1000, rng: fn min, _max -> min end)
    ...> |> Enum.to_list()
    [50, 100, 200, 400, 500]

# `apply_full`

```elixir
@spec apply_full(
  Enumerable.t(),
  keyword()
) :: Enumerable.t()
```

Applies Full Jitter to an existing delay stream.

Each delay in the input enumerable is capped at `:cap` and then randomized
uniformly in `[0, capped]`. Compatible with `Retry.DelayStreams.exponential_backoff/0`:

    import Retry.DelayStreams
    exponential_backoff() |> Jitter.apply_full(cap: 30_000) |> Stream.take(5)

## Examples

    iex> [100, 200, 400, 800, 2000]
    ...> |> Jitter.apply_full(cap: 1000, rng: fn _min, max -> max end)
    ...> |> Enum.to_list()
    [100, 200, 400, 800, 1000]

# `decorrelated`

```elixir
@spec decorrelated(
  pos_integer(),
  keyword()
) :: pos_integer()
```

Returns capped exponential delay with decorrelated jitter.

## Examples

    iex> Jitter.decorrelated(100, base: 100, cap: 30_000, rng: fn _min, max -> max end)
    300

    iex> Jitter.decorrelated(200, base: 100, cap: 30_000, rng: fn min, _max -> min end)
    100

    iex> Jitter.decorrelated(20_000, base: 100, cap: 30_000, rng: fn _min, max -> max end)
    30000

# `decorrelated_stream`

```elixir
@spec decorrelated_stream(keyword()) :: Enumerable.t()
```

Returns an infinite lazy stream of decorrelated jitter delays.

Unlike `full_stream/1` and `equal_stream/1`, this stream keeps the previous delay
as internal state. Each generated delay becomes the previous delay for the next step.

Use `Enum.take/2` or `Stream.take/2` to consume a finite number of values.

## Examples

    iex> Jitter.decorrelated_stream(base: 100, cap: 1000, rng: fn _min, max -> max end) |> Enum.take(5)
    [300, 900, 1000, 1000, 1000]

# `equal`

```elixir
@spec equal(
  non_neg_integer(),
  keyword()
) :: pos_integer()
```

Returns capped exponential delay with equal jitter.

## Examples

    iex> Jitter.equal(0, base: 100, cap: 30_000, rng: fn _min, max -> max end)
    100

    iex> Jitter.equal(3, base: 100, cap: 30_000, rng: fn _min, max -> max end)
    800

    iex> Jitter.equal(20, base: 100, cap: 1000, rng: fn _min, max -> max end)
    1000

# `equal_stream`

```elixir
@spec equal_stream(keyword()) :: Enumerable.t()
```

Returns an infinite lazy stream of equal jitter delays.

Each element is calculated from the next retry attempt. The delay is always
between half of the capped exponential delay and the full capped exponential delay.

Use `Enum.take/2` or `Stream.take/2` to consume a finite number of values.

## Examples

    iex> Jitter.equal_stream(base: 100, cap: 1000, rng: fn _min, max -> max end) |> Enum.take(5)
    [100, 200, 400, 800, 1000]

    iex> Jitter.equal_stream(base: 100, cap: 1000, rng: fn min, _max -> min end) |> Enum.take(5)
    [50, 100, 200, 400, 500]

# `full`

```elixir
@spec full(
  non_neg_integer(),
  keyword()
) :: pos_integer()
```

Returns capped exponential delay with full jitter.

## Examples

    iex> Jitter.full(0, base: 100, cap: 30_000, rng: fn _min, max -> max end)
    100

    iex> Jitter.full(3, base: 100, cap: 30_000, rng: fn _min, max -> max end)
    800

    iex> Jitter.full(20, base: 100, cap: 1000, rng: fn _min, max -> max end)
    1000

# `full_stream`

```elixir
@spec full_stream(keyword()) :: Enumerable.t()
```

Returns an infinite lazy stream of full jitter delays.

Each element is calculated from the next retry attempt:

    attempt 0, attempt 1, attempt 2, ...

Use `Enum.take/2` or `Stream.take/2` to consume a finite number of values.

## Examples

    iex> Jitter.full_stream(base: 100, cap: 1000, rng: fn _min, max -> max end) |> Enum.take(5)
    [100, 200, 400, 800, 1000]

# `no_jitter`

```elixir
@spec no_jitter(
  non_neg_integer(),
  keyword()
) :: pos_integer()
```

Returns capped exponential delay without jitter.

This is the baseline — no randomness, just exponential growth.
Use this only as a reference; in production prefer `full/2` or `decorrelated/2`.

## Examples

    iex> Jitter.no_jitter(0, base: 100, cap: 30_000)
    100

    iex> Jitter.no_jitter(3, base: 100, cap: 30_000)
    800

    iex> Jitter.no_jitter(20, base: 100, cap: 1000)
    1000

---

*Consult [api-reference.md](api-reference.md) for complete listing*
