Message Reliability Protocol — retransmission state and backoff.
Pure struct with no GenServer. Timer scheduling is the caller's
responsibility (use Process.send_after in a GenServer).
Backoff formula (Matter spec section 4.11.8)
timeout = base_interval * 1.1 * 1.6^attempt * (1 + jitter)where base_interval is 300ms (active) or 500ms (idle). Max transmissions = 5 (1 original + 4 retries).
Summary
Functions
Timeout in ms before sending a standalone ACK.
Compute retransmission timeout in milliseconds.
Return the exchange id associated with a pending message counter.
Maximum number of transmissions (initial + retries).
Create new MRP state.
Record that an ACK was received for an exchange.
Handle a retransmission timer firing.
Check if there is a pending retransmission for an exchange.
Record an outgoing reliable message. The caller should schedule
the first retransmission timer using backoff_ms/3 with attempt 0.
Move a pending retransmission to a new message counter after retransmit.
Types
@type pending() :: %{ message: binary(), attempt: non_neg_integer(), exchange_id: non_neg_integer() }
@type t() :: %MatterEx.Protocol.MRP{ mode: :active | :idle, pending: %{required(non_neg_integer()) => pending()} }
Functions
@spec ack_timeout_ms() :: non_neg_integer()
Timeout in ms before sending a standalone ACK.
@spec backoff_ms(t(), non_neg_integer(), keyword()) :: non_neg_integer()
Compute retransmission timeout in milliseconds.
Pass deterministic: true to remove jitter (for testing).
@spec exchange_id(t(), non_neg_integer()) :: non_neg_integer() | nil
Return the exchange id associated with a pending message counter.
@spec max_transmissions() :: non_neg_integer()
Maximum number of transmissions (initial + retries).
Create new MRP state.
@spec on_ack(t(), non_neg_integer()) :: {:ok, t()} | {:error, :not_found}
Record that an ACK was received for an exchange.
@spec on_timeout(t(), non_neg_integer(), non_neg_integer()) :: {:retransmit, binary(), t()} | {:give_up, t()} | {:already_acked, t()}
Handle a retransmission timer firing.
Returns:
{:retransmit, message, new_state}— resend the message{:give_up, new_state}— max retransmissions reached{:already_acked, new_state}— exchange already acknowledged
@spec pending?(t(), non_neg_integer()) :: boolean()
Check if there is a pending retransmission for an exchange.
@spec record_send(t(), non_neg_integer(), binary(), non_neg_integer() | nil) :: t()
Record an outgoing reliable message. The caller should schedule
the first retransmission timer using backoff_ms/3 with attempt 0.
@spec rekey(t(), non_neg_integer(), non_neg_integer()) :: t()
Move a pending retransmission to a new message counter after retransmit.