# `MobDev.Bench.Reconnector`
[🔗](https://github.com/genericjam/mob_dev/blob/master/lib/mob_dev/bench/reconnector.ex#L1)

Auto-reconnect logic for the bench's BEAM dist connection.

When a probe says the dist connection has dropped (`:alive_epmd_only` or
`:alive_dist_only` after an RPC timeout), we want to attempt to reconnect
automatically rather than leaving the bench in a stuck state for the rest
of the run.

This module is *pure logic* — no GenServer, no timers. The bench polling
loop calls `tick/2` once per cycle, which decides whether to attempt a
reconnect based on the current reachability and elapsed time since the
last attempt. This keeps the reconnect logic testable and lets the
caller control the cadence.

## Backoff schedule (defaults)

    1st attempt: immediate
    2nd attempt: 2 s after 1st
    3rd attempt: 4 s after 2nd
    4th attempt: 8 s after 3rd
    Subsequent: 30 s cap

Reset to immediate on a successful reconnect.

# `t`

```elixir
@type t() :: %MobDev.Bench.Reconnector{
  attempts: non_neg_integer(),
  cookie: atom(),
  last_attempt_ms: integer() | nil,
  max_backoff_ms: pos_integer(),
  node: atom(),
  total_reconnects: non_neg_integer()
}
```

# `current_backoff_ms`

```elixir
@spec current_backoff_ms(t()) :: non_neg_integer()
```

Returns the backoff (in ms) that applies to the *next* attempt.

    iex> r = MobDev.Bench.Reconnector.new(:node@host, :secret)
    iex> MobDev.Bench.Reconnector.current_backoff_ms(r)
    0

    iex> r = %{MobDev.Bench.Reconnector.new(:node@host, :secret) | attempts: 3}
    iex> MobDev.Bench.Reconnector.current_backoff_ms(r)
    8000

# `new`

```elixir
@spec new(atom(), atom(), keyword()) :: t()
```

Initialise a reconnector for `node` with cookie. Optional `:max_backoff_ms`.

# `record_success`

```elixir
@spec record_success(t()) :: t()
```

Record that the most recent reconnect attempt succeeded — resets the
backoff counter and bumps the total_reconnects counter.

# `tick`

```elixir
@spec tick(t(), MobDev.Bench.Probe.t() | atom(), integer()) ::
  {:no_action | :attempt, t()}
```

Decide whether the caller should attempt a reconnect right now, given the
current probe state and current time. Returns `{action, updated_reconnector}`.

Actions:
- `:no_action` — connection is healthy or it's not time yet
- `:attempt` — caller should try `Node.connect(reconnector.node)` now

After a successful reconnect, call `record_success/1` to reset the backoff.

---

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